home *** CD-ROM | disk | FTP | other *** search
/ QRZ! Ham Radio 6 / QRZ Ham Radio Callsign Database - Volume 6.iso / mac / files / amiga / csrc720j.lzh / mbmail.c < prev    next >
C/C++ Source or Header  |  1993-08-14  |  65KB  |  2,873 lines

  1. /*
  2.  *  MBMAIL.C - 10/03/92 The message file stuff, except for forwarding.
  3.  */
  4.  
  5. #include "mb.h"
  6. #ifdef MCH_AMIGA
  7. extern char optflags[];
  8. extern char tmpstr[];
  9. extern short all_number;
  10. extern short gotmail;
  11. extern short debug;
  12. short thebox = 0,kambbs = 0;
  13. extern short interflag;
  14. extern int srcmd_flag;     /* for SR */
  15. struct lst_msg last_msg;
  16. #endif
  17.  
  18. #define btmax 112   /* Max text in beacon line */
  19. #define ln_hier 64
  20.  
  21. char  orgmsg[6], orgbbs[7], orgtime[5], orgdate[7];
  22.  
  23. char  *mbfile, *mbbfile, *msgdir, *bidfile, *stfile;
  24. char bbidfile[] = "BID.TMP";
  25.  
  26.  
  27. char  *ufwd;  /* Calls with unread msgs, for BT */
  28. char  *bfwd;  /* Calls with unread msgs, for forwarding */
  29.  
  30. short ufwdm, ufwdn, bfwdm, bfwdn, bidnum;
  31. short tstaleb, tstalen, tstaleu;
  32. short tstale1, tstale2, tstale3;
  33. short rstale1, rstale2, rstale3;
  34. int hasbid, needbid, holdit;
  35.  
  36. char  *mm[num_mm];
  37. char  wpcall[ln_call];
  38. XBBS  *xbbs;
  39. HOLD  *hold;
  40.  
  41. MAIL_HDR  *mfhs;
  42. MSG_HDR   *tmmhs;
  43.  
  44. FILE *bfl;
  45.  
  46. #ifndef MCH_AMIGA
  47. int mfl, mflb;
  48. #else
  49. int mfl = -1, mflb = -1;
  50. #endif
  51.  
  52. msgfile(p, n)
  53. char *p;
  54. word n;
  55. {
  56.   sprintf(p, "%s%u", msgdir, n);
  57. }
  58.  
  59. /*
  60.  *  Open file to hold BIDs
  61.  */
  62.  
  63. opnbid()
  64. {
  65. #ifndef MCH_AMIGA
  66.   if ((bfl = fopen(bidfile, "a+")) is NULL) { nofile(bidfile); exit(1); }
  67. #else
  68. /* This does not need locking since it only opens and closes the file */
  69.    if((bfl = fopen(bidfile, "a+")) is NULL) {
  70.       nofile(bidfile);
  71.       done(1);
  72.    }
  73. #endif
  74.   fclose(bfl);
  75. }
  76.  
  77. /*
  78.  *  Write message header.
  79.  */
  80.  
  81. wt_mmhs()
  82. {
  83.   if (port->mmhs->rn) write_rec (mfl, port->mmhs->rn, (char *)port->mmhs);
  84. }
  85.  
  86.  
  87. /*
  88.  *  Get message title.
  89.  */
  90.  
  91. get_title()
  92. {
  93.   while(!getdat());
  94.   remnl(port->line);
  95.   strncpy(port->mmhs->title, port->line, mhtitl);
  96. }
  97.  
  98. /*
  99.  *  Parse the [@ bbs] and [< from] fields of a command.
  100.  */
  101.  
  102. atfrom(i)
  103. int i;
  104. {
  105.   if (*port->fld[i] is '<') pcall(port->mmhs->from, port->fld[i + 1]);
  106.   else if (*port->fld[i] is '@')
  107.   {
  108.     pcall(port->mmhs->bbs, port->fld[i +1]);
  109.     if ((strchr(port->fld[i + 1], '.')) is NULL)
  110.     { chkhier(); return; }
  111.     port->mmhs->ext = 2;
  112.     fill (port->mmhs->call, '\0', 124);
  113.     strncpy(port->mmhs->call[0], port->fld[i + 1], ln_hier);
  114.   }
  115. }
  116.  
  117. /*
  118.  *  Parse the fields of a send command.
  119.  */
  120.  
  121. pfld()
  122. {
  123. #ifdef MCH_AMIGA
  124.    short life = 0;         /* ARF ARF! */
  125.    short ltmp;
  126. /* for SR command. Any SR command with one or more arguments is
  127.    an error
  128. */
  129.    if(port->opt2 == 'R') {
  130.       port->msg = mwhat;
  131.       return(0);
  132.    }
  133. #endif
  134.   hasbid = false;
  135.  
  136.   port->mmhs->type = port->opt2;
  137.   pcall(port->mmhs->to, port->fld[1]);
  138.  
  139.   /*  If a message is to an individual and type is blank,
  140.    *  automatically make it a private message, else make it a bulletin.
  141.    */
  142.  
  143.   if (port->opt2 is ' ')
  144.   if (iscall(port->mmhs->to)) port->mmhs->type = 'P';
  145.      else port->mmhs->type = 'B';
  146.  
  147.   strncpy(port->mmhs->from, port->user->call, ln_call);
  148.   fill(port->mmhs->bbs, ' ', ln_call);
  149.   fill(port->mmhs->bid, ' ', ln_bid);
  150.   fill(port->mmhs->fwdc, '\0', ln_call);
  151.   port->mmhs->ext = 0;
  152.  
  153. #ifdef MCH_AMIGA
  154.    /* Check the message type and do some fancy overriding where necessary */
  155.    /* In particular there's a new fix here specifically for the KAM BBS in
  156.       its V3.01 so that a personal message to an invalid callsign is forced
  157.       to be a Bulletin
  158.    */
  159.    switch(port->mmhs->type) {
  160.  
  161.    case 'P':
  162.       if(!kambbs)break;
  163.       if(!iscall(port->mmhs->to)) {
  164.          port->mmhs->type = 'B';
  165.       }
  166.       break;
  167.    /* If type is blank then set it to Personal if the 'to' is a valid
  168.       call, otherwise make it a bulletin
  169.    */
  170.    case ' ':
  171.  
  172.       if(iscall(port->mmhs->to)) {
  173.          port->mmhs->type = 'P';
  174.       }
  175.       else {
  176.          /* If the TO call is one letter long then someone is trying to send
  177.             a THEBOX control message. Throw it away.
  178.          */
  179.          if((port->mmhs->to[1] == ' ') || (port->mmhs->to[1] == 0)) {
  180.             outstr("No - I don't use control messages\n");
  181.             needbid = 0;
  182.             return(0);
  183.          }
  184.          port->mmhs->type = 'B';
  185.       }
  186.       break;
  187.    /* THEBOX can send a 'S$' command. Set the type to Bulletin.
  188.       THEBOX only accepts an 'S' command and ignores any option
  189.       such as 'P', 'B' etc. If the message is TO a valid call
  190.       then it is marked 'P'. If it is not 'P', it will mark it
  191.       as 'B' if either there is no '@' field or if the '@' field
  192.       is a valid call. If it is not 'B' but the FROM call is
  193.       valid then it marks the message as '$'. If the TO field
  194.       is only one character long then the message is marked 'C'.
  195.       Failing all this the message is marked 'H' and is held.
  196.    */
  197.    case '$':
  198.       port->mmhs->type = 'B';
  199.       break;
  200.    /* THEBOX can also send 'SC' which is some form of control message
  201.       that doesn't mean anything to us. Reject it.
  202.    */
  203.    case 'C':
  204.       outstr("No - I don't use control messages\n");
  205.       needbid = 0;
  206.       return(0);
  207.    }
  208.    /* The switch may have changed the type so we have to change the
  209.       opt2 as well. They are almost the same thing.
  210.    */
  211.    port->opt2 = port->mmhs->type;
  212.    /* Force Personal messages to require a BID .... for MID code */
  213.    if(port->mmhs->type == 'P')needbid = 1;
  214.  
  215.    /* THEBOX can send us a message lifetime indicator at the end of an 'S'
  216.       command. Save the number for later use but remove the field so the
  217.       remaining code will see the bid at the end (if it is there).
  218.    */
  219.    life = -1;
  220.    if(*port->fld[port->flds-1] is '#') {
  221.       ltmp = atoi(&port->fld[port->flds-1][1]);
  222.       if((ltmp > 0) && (ltmp < 256))life = ltmp;
  223.       port->flds--;
  224.    }
  225.    /* If this is a bulletin and the lifetime isn't set then default it.
  226.    */
  227.    if((port->mmhs->type == 'B') && (life == -1))
  228.       life = tstaleb;
  229. #endif
  230.  
  231.   if (port->flds > 3) atfrom(port->flds - 2);
  232.   if (port->flds > 5) atfrom(port->flds - 4);
  233.  
  234. #ifdef MCH_AMIGA
  235.    /* routine added to mbuser to see if we have the user 'to' in our
  236.       user record file. If so, then use our @bbs rather than the one
  237.       in the message. We presume that if that user's name is on file
  238.       here and we also have an @bbs for him, then it is likely to
  239.       be just as accurate, or better, than the one in the message.
  240.       In particular, this is useful for setting the @bbs field when
  241.       a user leaves it out of an 'S' command.
  242.    */
  243.    replace_bbs();
  244.  
  245.  
  246. #endif
  247.  
  248.   if (port->flds > 2)
  249.   if(*port->fld[port->flds-1] is '$')
  250.   {
  251. /* MCH_AMIGA */
  252.     if (*(port->fld[port->flds - 1] + 1)/* isnt NULL*/)
  253.     {
  254.     strncpy(port->mmhs->bid, port->fld[port->flds - 1] + 1, ln_bid);
  255.     hasbid = true;
  256.     }
  257.     if (port->flds > 4) atfrom(port->flds - 3);
  258.     if (port->flds > 6) atfrom(port->flds - 5);
  259.   }
  260.  
  261.   initmsg(true);  
  262.  
  263. #ifdef MCH_AMIGA
  264. /* Store the message lifetime which will be set to the '#' field of
  265.    a received message if it exists. Otherwise it will be the lifetime
  266.    default for a bulletin or zero.
  267. */
  268.    if(life)port->mmhs->lifetime = life;
  269.  
  270.    /* Check the reject.btn file to see if this message should be
  271.       rejected.
  272.    */
  273.    if(test_reject()) {
  274.       outstr("No - Rejected\n");
  275.       needbid = 0;
  276.       return(0);
  277.    }
  278.    /* Checks for unknown @BBS field and leaves it in tmpstr[0] if so */
  279.    /* Must not use tmpstr between here and the warning message */
  280.    ltmp = test_bbs();
  281. #endif
  282.  
  283.   if(!s_mart) {
  284. #ifdef MCH_AMIGA
  285. /* Part of the 'SR' command */
  286.    if(last_msg.type)prt_subj();
  287. /* WATCH OUT .... I've bracketed this else across these two #ifdefs */
  288.    else {
  289.       if(ltmp) {
  290.          outstr("WARNING: The @BBS field '");
  291.          outstr(tmpstr);
  292.          outstr("' is not known at this BBS\n");
  293.          outstr("         Your message may not be delivered ... continue\n");
  294.       }
  295.  
  296. #endif
  297.     if (port->user->options & (u_bbs | u_expert)) outstr("Sj:\n");
  298.     else prtx(mm[0]);
  299. #ifdef MCH_AMIGA
  300.    }
  301. /* Part of SR command - don't call get_title */
  302.    if(last_msg.type == 0)
  303. #endif
  304.     get_title();
  305. #ifndef MCH_AMIGA
  306.     return;
  307. #else
  308.     return(1);
  309. #endif
  310.   }
  311.   else {  
  312. #ifdef MCH_AMIGA
  313.       /* Check for unwanted bulletins.
  314.          If this is a bulletin or it has a BID then see if we
  315.          want this bulletin.
  316.          If the @bbs has a corresponding
  317.          msgs/bbs.dis then accept it, otherwise No tnx
  318.       */
  319.       if(optflags[0] && (port->mmhs->type == 'B')) {
  320.          if(tmpstr[0] == 0) {
  321.             outstr("No - Don't want it tnx\n");
  322.             needbid = 0;
  323.             return(0);
  324.          }
  325.       }
  326. #endif
  327.     if (hasbid) {
  328.       checkbid();
  329.       if (!needbid) {
  330.    outstr("NO\n");
  331.    sprintf(port->mmhs->title, "<<%6.6s - %s>>",
  332.         port->user->call, port->fld[port->flds-1]);
  333.    wt_mmhs();
  334. #ifndef MCH_AMIGA
  335.    return;
  336. #else
  337.         return(0);
  338. #endif
  339.       }
  340.       prtx("OK\n");
  341.       get_title();
  342. #ifndef MCH_AMIGA
  343.       return;
  344. #else
  345.       return(1);
  346. #endif
  347.     }
  348.     else {
  349.       prtx("OK\n");
  350.       get_title();
  351.       needbid = true;     /* will check and may assign one later */
  352. #ifndef MCH_AMIGA
  353.       return;
  354. #else
  355.       return(1);
  356. #endif
  357.     }
  358.   }
  359. #ifdef MCH_AMIGA
  360. /* Not sure it can get here ... but just in case */
  361.       return(1);
  362. #endif
  363. }
  364.  
  365. /*
  366.  *  Create the header line.
  367.  */
  368.  
  369. makehdr()
  370. {
  371.   register char st,ef,ht;
  372. #ifdef MCH_AMIGA
  373.    register char *p;
  374. #endif
  375.  
  376.   st = 'N';
  377.   ht = ' ';
  378.  
  379. #ifndef MCH_AMIGA
  380.   if (port->mode & ops)
  381.   {
  382.     if (port->mmhs->stat & m_stale) st = 'O';
  383.     if (port->mmhs->stat & m_bull) st = '$';
  384.     if (port->mmhs->stat & m_hold)
  385.     {
  386.       st = 'H';
  387.       if(port->mmhs->htype) ht = port->mmhs->htype;
  388.     }
  389.   }
  390. #endif
  391.   if (port->mmhs->stat & m_fwd)   st = 'F';
  392.   if (port->mmhs->stat & m_read)  st = 'Y';
  393.   if (port->mmhs->stat & m_kill)  st = 'K';
  394.   if (port->mmhs->stat & m_busy)  st = 'B';
  395. #ifdef MCH_AMIGA
  396. /* Show the sysop the true state of the messages. Doing this first means
  397.    all the other states e.g. 'Y' override these
  398. */
  399.   if (port->mode & ops)
  400.   {
  401.     if (port->mmhs->stat & m_stale) st = 'O';
  402.     if (port->mmhs->stat & m_bull) st = '$';
  403.     if (port->mmhs->stat & m_hold) st = 'H';
  404.   }
  405. #endif
  406.   if (port->mmhs->ext is 2) ef = '*'; else ef = ' ';
  407. #ifndef MCH_AMIGA
  408.   sprintf(tmp->scr,"%5u %c%c%c%5u %6.6s %6.6s %6.6s%c%3u %4.4s/%4.4s %s\n",
  409.     port->mmhs->number, port->mmhs->type, st, ht, port->mmhs->size,
  410.     port->mmhs->to,port->mmhs->from,port->mmhs->bbs,ef,port->mmhs->read,
  411.     port->mmhs->date + 2, port->mmhs->time, port->mmhs->title);
  412. #else
  413. /* Don't let the title exceed the line length */
  414.    sprintf(tmpstr,"%-27.27s",port->mmhs->title);
  415.    for(p=tmpstr;*p;p++);
  416.    p--;
  417.    while((p > tmpstr) && (*p == ' '))p--;
  418.    p++;
  419.    *p = 0;
  420.   sprintf(tmp->scr,"%5u %c%c%c%5u %6.6s %6.6s %6.6s%c%3u %4.4s/%4.4s %s\n",
  421.     port->mmhs->number, port->mmhs->type, st, ht, port->mmhs->size,
  422.     port->mmhs->to,port->mmhs->from,port->mmhs->bbs,ef,port->mmhs->read,
  423.     port->mmhs->date + 2, port->mmhs->time, tmpstr);
  424. #endif
  425.  
  426.   if ((port->opt2 is 'K') and (port->mode & ops))
  427.   {
  428.     if (!port->mmhs->fport) port->mmhs->fport = ' ';
  429.     sprintf(tmp->scr+37, ">%6.6s %c->%6.6s %s\n",port->mmhs->fwdd,
  430.        port->mmhs->fport, port->mmhs->fwdc, port->mmhs->title);
  431.   }
  432. }
  433.  
  434. /*
  435.  * Write mail.dat header into text file
  436.  */
  437.  
  438. makehdr2()
  439. {
  440.   register char st, c;
  441.   int msfl;
  442.   char flags[mmesn];
  443.   fill (flags, ' ',mmesn);
  444.   fill (tmp->scr, '\0', 256);
  445.   tmp->scr[254] = '\r'; tmp->scr[255] = '\n';
  446. #ifdef MCH_AMIGA
  447. /* Save the lifetime in the header so that mbrestm can recover it */
  448.    tmp->scr[252] = port->mmhs->lifetime;
  449. #endif
  450.   if (port->mmhs->ext is 1)
  451.   {
  452.     for (c=0; c < port->mmhs->count; c++)
  453.     flags[c] = port->mmhs->flag[c] + '0';
  454.   }
  455.   st = 'N';
  456.   if (port->mmhs->stat & m_busy)  st = 'B';
  457.   if (port->mmhs->stat & m_stale) st = 'O';
  458.   if (port->mmhs->stat & m_fwd)   st = 'F';
  459.   if (port->mmhs->stat & m_bull)  st = '$';
  460.   if (port->mmhs->stat & m_hold)  st = 'H';
  461.   if (port->mmhs->stat & m_read)  st = 'Y';
  462.   if (port->mmhs->stat & m_kill)  st = 'K';
  463.   sprintf(tmp->scr,
  464.       "%5u %c%c %5u %6.6s %6.6s %6.6s %6.6s %4.4s %-12.12s %5u\r\n",
  465.     port->mmhs->number, port->mmhs->type, st, port->mmhs->size,
  466.     port->mmhs->to, port->mmhs->from, port->mmhs->bbs,
  467.     port->mmhs->date, port->mmhs->time, port->mmhs->bid, port->mmhs->read);
  468.   if (port->mmhs->ext is 2)
  469.        sprintf(tmp->scr+68, "%c %s\r\n%s\r\n", port->mmhs->ext +'0',
  470.        port->mmhs->call, port->mmhs->title);
  471.   else sprintf(tmp->scr+68, "%c %13.13s   \r\n%s\r\n", port->mmhs->ext +'0',
  472.        flags, port->mmhs->title);
  473.  
  474.   msgfile(port->cmd, port->mmhs->number);
  475.   if ((msfl = open(port->cmd, O_WRONLY | O_BINARY)) < 0) return;
  476.   write_rec(msfl, 0, (char *)tmp->scr);
  477.   close(msfl);
  478. }
  479.  
  480. /*
  481.  *  Print a message header.
  482.  */
  483.  
  484. char prthdr(tit, max_title)
  485. int tit, max_title;
  486. {
  487.   char *a, *b;
  488.  
  489.   register short i;
  490.   register short docc;
  491.  
  492. #ifndef MCH_AMIGA
  493.   if (tit) prtx(mm[3]);
  494. #else
  495. /* If we print a title then start the line counter as well. */
  496.   if (tit) {
  497.       prtx(mm[3]);
  498.       pgst(NULL);
  499.       pgck();
  500.   }
  501. #endif
  502.   makehdr();
  503.   if (strlen(tmp->scr) > 79)
  504.   {
  505.     if (!max_title)
  506.     {
  507.       tmp->scr[79] = '\n';
  508.       tmp->scr[80] = '\0';
  509.     }
  510.     else if (lstquit()) return ('Q');
  511.   }
  512.   outstr(tmp->scr);
  513.   if (lstquit()) return ('Q');
  514.   if((port->opt1 is 'L') and
  515.   ((*port->fld[1] isnt ';') and
  516.   (*port->fld[2] isnt ';') and (*port->fld[3] isnt ';')))
  517.      return(' ');
  518.   if(*port->mmhs->fwdc) if (port->mode & ops)
  519.   {
  520.     sprintf(port->line,
  521.       "   <<%6.6s  F->%6.6s", port->mmhs->fwdd, port->mmhs->fwdc);
  522.     outstr(port->line);
  523.     if (!(port->mmhs->ext))
  524.       {
  525.    outchar('\n');
  526.    if (lstquit()) return ('Q');
  527.       }
  528.   }
  529.   if (port->mmhs->ext is 2)
  530.   {
  531.     outstr("    EF:");
  532.     outstr(port->mmhs->call[0]);
  533.     outchar('\n');
  534.     if (lstquit()) return ('Q');
  535.   }
  536.   if (port->mmhs->ext is 1) if (port->mode & ops)
  537.   {
  538.     docc = false;
  539.     for (i = 0; i < port->mmhs->count; i++) if (port->mmhs->flag[i])
  540.      docc = true;
  541.  
  542.     if (docc)
  543.     {
  544.       outstr("    cc:");
  545.       for (i = 0; i < port->mmhs->count; i++)
  546.       {
  547.    if (port->mmhs->flag[i]) outchar(' '); else outstr(" *");
  548.    outnb(port->mmhs->call[i], ln_call);
  549.       }
  550.       outchar('\n');
  551.       if (lstquit()) return ('Q');
  552.     }
  553.   }
  554.   if (port->mode & ops) if (*port->mmhs->bid isnt ' ')
  555.     {
  556.     outstr("   BID: ");
  557.     a = port->line;
  558.     b = port->mmhs->bid;
  559.     unbl(a, b, ln_bid);
  560.     outstr(port->line);  outchar('\n');
  561.     if (lstquit()) return ('Q');
  562.   }
  563. #ifdef MCH_AMIGA
  564.    if((port->mode & ops) && (port->mmhs->type == 'B')) {
  565.       sprintf(tmpstr,"   Life: %u\n",port->mmhs->lifetime);
  566.       outstr(tmpstr);
  567.       if(lstquit())return('Q');
  568.    }
  569. #endif
  570.   return(' ');
  571. }
  572.  
  573. lstquit()
  574. {
  575.   if ((pgck() is 'Q') or (chkdis())) return true;
  576.   return false;
  577. }
  578.  
  579. /*
  580.  *  Read the message, look for the last bbs header.
  581.  *  Set the @ field of the current message to the "at bbs" in that header.
  582.  */
  583.  
  584. findat()
  585. {
  586.   register short i;
  587.  
  588.   fill(port->mmhs->bbs, ' ', ln_call);
  589.   msgfile(port->line, port->mmhs->number);
  590.   if ((port->fl = fopen(port->line, "r")) is NULL) { nofile(port->line); return; }
  591.   fseek(port->fl, (long)RECSIZE, 0);
  592.   while(fgets(port->line, linelen, port->fl) isnt NULL)
  593.   {
  594.     if (!parsehd(port->line)) break;
  595.     pcall(port->mmhs->bbs, orgbbs);
  596.   }
  597.   fclose (port->fl);
  598.   chkhier();
  599. }
  600.  
  601. /*
  602.  *  Parse a message header line.
  603.  */
  604.  
  605. parsehd(in)
  606. char *in;
  607. {
  608.   register char *p;
  609.   register int count, n;
  610.  
  611.   if (!ishead(in)) return false;
  612.  
  613.   p = strchr(in, 'R');
  614.   p++;
  615.  
  616.   if (*p is ':') p++;
  617.   if (*p is ' ') p++;
  618.   count = 6;
  619.   n = 0;
  620.   while (*p and count--)
  621.   {
  622.     if (!isdigit(*p)) break;
  623.     orgdate[n++] = *p++;
  624.   }
  625.   orgdate[n] = '\0';
  626.  
  627.   if (*p is '/') p++;
  628.  
  629.   count = 4;
  630.   n = 0;
  631.   while (*p and count--)
  632.   {
  633.     if (!isdigit(*p)) break;
  634.     orgtime[n++] = *p++;
  635.   }
  636.   orgtime[n] = '\0';
  637.  
  638.  
  639.   if ((p = strchr(in, '@')) is NULL) return false;
  640.   {
  641.     p++;
  642.  
  643. /* skip colon or a space in @:call  OR @ call */
  644.  
  645.     while ((*p is ':')or(*p is ' ')) p++;
  646.     count = ln_call;
  647.     n = 0;
  648.     while (*p and count--)
  649.     {
  650.       if (!isalnum(*p)) break;
  651.       toupper(*p);
  652.       orgbbs[n++] = *p++;
  653.     }
  654.     orgbbs[n] = '\0';
  655.   }
  656.  
  657.   if (((p = strrchr(in, '#')) isnt NULL) and (*(p+1) is ':'))
  658.   {
  659.     p++;
  660.  
  661.     while ((*p is ':')or(*p is ' ')) p++;
  662.     count = 5;
  663.     n = 0;
  664.     while (*p and count--)
  665.     {
  666.       if (!isalnum(*p)) break;
  667.       orgmsg[n++] = *p++;
  668.     }
  669.     orgmsg[n] = '\0';
  670.   }
  671.   else
  672.   {
  673.     p = strchr(in, '@');
  674.     p--; count = 5;
  675.     while(count-- and *p isnt ' ') p--;
  676.     p++;
  677.     if (*p is '<') p++;
  678.     count = 5;
  679.     n = 0;
  680.     while (*p and count--)
  681.     {
  682.       if (*p is '@') break;
  683.       orgmsg[n++] = *p++;
  684.     }
  685.     orgmsg[n] = '\0';
  686.   }
  687.   return true;
  688. }
  689.  
  690.  
  691. /*
  692.  *  Find a message given it's number.
  693.  */
  694.  
  695. findmsg(nr)
  696. word nr;
  697. {
  698.   register word i;
  699.  
  700. #ifdef MCH_AMIGA
  701.    check_mail();
  702.    unlock_mail();
  703. #endif
  704.   for (i = mfhs->last; i; i--)
  705.   {
  706.     read_rec(mfl, i, (char *)port->mmhs);
  707.     if (port->mmhs->number is nr) return true;
  708.   }
  709.   return false;
  710. }
  711.  
  712. /*
  713.  *  Create the distribution list, if required.
  714.  */
  715.  
  716. dodis()
  717. {
  718.   register FILE *dfl;
  719. #ifndef MCH_AMIGA
  720.   if (port->mmhs->ext is 2) return;
  721.   port->mmhs->ext = 0;
  722. #else
  723. /* The code has been modified so that if ->ext is non-zero then dodis()
  724.    has already been called ( == 1) or doesn't need to be called ( == 2).
  725. */
  726.   if (port->mmhs->ext) return;
  727. #endif
  728.   if (*port->mmhs->bbs is ' ') return;
  729.  
  730.   unbl(tmp->scr, port->mmhs->bbs, ln_call);
  731.  
  732.   strcpy(port->line, msgdir);
  733.   strcat(port->line, tmp->scr);
  734.   strcat(port->line, ".DIS");
  735.  
  736.   if ((dfl = fopen(port->line, "r")) is NULL) return;
  737.  
  738.   port->mmhs->ext = 1 ;
  739.  
  740.   for (port->mmhs->count = 0;
  741.     (port->mmhs->count < mmesn) and (fgets(tmp->scr, scrmax, dfl) isnt NULL);
  742.     port->mmhs->count++)
  743.   {
  744.     strupr(tmp->scr);
  745.     pcall(port->mmhs->call[port->mmhs->count], tmp->scr);
  746. #ifdef MCH_AMIGA
  747. /* Blank lines are bad news! */
  748.     if(port->mmhs->call[port->mmhs->count][0] == ' ') {
  749.        port->mmhs->count--;
  750.        continue;
  751.     }
  752. #endif
  753.     if(matchn(port->mmhs->call[port->mmhs->count], port->user->call, ln_call))
  754.     port->mmhs->flag[port->mmhs->count] = false;
  755.     else port->mmhs->flag[port->mmhs->count] = true;
  756.   }
  757.   fclose(dfl);
  758. }
  759.  
  760. /*
  761.  *  Do we hold this message?
  762.  */
  763.  
  764. ishold(c)
  765. char *c;
  766. {
  767.   register HOLD *hp;
  768.  
  769.   for (hp = hold; hp isnt NULL; hp = hp->next)
  770.   if (matchn(hp->call, c, ln_call)) return true;
  771.  
  772.   return false;
  773. }
  774.  
  775. /*
  776.  *  Create message utilities - initmsg and cremsg.
  777.  *  Used by "send message", "make message from file",
  778.  *  "kill msg" (service messages), "copy message".
  779.  */
  780.  
  781. initmsg(h)
  782. int h;
  783. {
  784.   if (s_flag & s_dv) begin_lock();
  785. #ifdef MCH_AMIGA
  786.    check_mail();
  787. #else
  788.   read_rec(mfl, 0, (char *)mfhs);
  789. #endif
  790.  
  791.   port->mmhs->rn = mfhs->next++;
  792.   port->mmhs->number = mfhs->next_msg++;
  793. #ifdef MCH_AMIGA
  794.    set_mail((long)mfhs->next);
  795. #endif
  796.   port->mmhs->stat = m_busy;
  797. #ifndef MCH_AMIGA
  798.   strncpy(port->mmhs->date, l_date, ln_date);
  799.   strncpy(port->mmhs->time, l_time, ln_time);
  800. #else
  801. /* Use UTC for the file creation date. */
  802.   strncpy(port->mmhs->date, z_date, ln_date);
  803.   strncpy(port->mmhs->time, z_time, ln_time);
  804. #endif
  805.   port->mmhs->read = 0;
  806.   port->mmhs->size = 0;
  807.   if(port->mmhs->ext isnt 2) fill(port->mmhs->call, '\0', 124);
  808.   if(h)sprintf(port->mmhs->title, "<<%6.6s -- disconnected>>",port->user->call);
  809.   pcall(port->mmhs->fwdd, port->user->call, ln_call);
  810.  
  811. #ifdef MCH_AMIGA
  812.    port->mmhs->lifetime = 0;
  813. #endif
  814. /*
  815.  *  Clean up the file header.
  816.  */
  817.  
  818.   if (!mfhs->first) mfhs->first = port->mmhs->rn;
  819.   mfhs->last = port->mmhs->rn;
  820.   mfhs->count++;
  821.   write_rec(mfl, 0, (char *)mfhs);
  822.   wt_mmhs();
  823.   mfhs->next_msg--;
  824.   if (s_flag & s_dv) end_lock();
  825. #ifdef MCH_AMIGA
  826.    unlock_mail();
  827.    titles();
  828. #endif
  829. }
  830.  
  831. cremsg()
  832. {
  833.   register XBBS *xp;
  834.  
  835.   port->mmhs->stat   = 0;
  836. #ifndef MCH_AMIGA
  837.   strncpy(port->mmhs->date, l_date, ln_date);
  838.   strncpy(port->mmhs->time, l_time, ln_time);
  839. #else
  840. /* Use UTC for the file creation date. */
  841.   strncpy(port->mmhs->date, z_date, ln_date);
  842.   strncpy(port->mmhs->time, z_time, ln_time);
  843. #endif
  844.   port->mmhs->read = 0;
  845.   port->mmhs->size = filesize;
  846.  
  847.   for (xp = xbbs; xp isnt NULL; xp = xp->next)
  848.   if (wcm(xp->from, port->mmhs->bbs))
  849.   {
  850.     strncpy(port->mmhs->bbs, xp->to, ln_call);
  851.     if (port->mmhs->ext is 2) port->mmhs->ext = 0;
  852.     if (wcm(xp->from, xp->to)) port->mmhs->stat setbit m_bull;
  853.     break;
  854.   }
  855.  
  856.   if (ishold(port->mmhs->to))
  857.   {
  858.     port->mmhs->stat = m_hold;
  859.     port->mmhs->htype = 'T';
  860.   }
  861.   if (ishold(port->mmhs->from))
  862.   {
  863.     port->mmhs->stat = m_hold;
  864.     port->mmhs->htype = 'F';
  865.   }
  866.   if (ishold(port->mmhs->bbs))
  867.   {
  868.     port->mmhs->stat = m_hold;
  869.     port->mmhs->htype = 'B';
  870.   }
  871.  
  872.   if (ishold("HUSER "))
  873.   {
  874.     if (!(port->user->options & (u_sysop|u_bbs)))
  875.     if (port->mmhs->type is 'B')
  876.     {
  877.       port->mmhs->stat = m_hold;
  878.       port->mmhs->htype = 'H';
  879.     }
  880.   }
  881.  
  882.   if (holdit) port->mmhs->stat = m_hold;
  883.  
  884.   if (*port->mmhs->bid isnt ' ')
  885.   {
  886.     checkbid();
  887.     if (hasbid) if (!holdit) if (needbid)  putbid(true);
  888.   }
  889.   dodis();
  890.  
  891.   if ((port->mmhs->ext is 1) and (*port->mmhs->bid is ' '))
  892.   {
  893.     port->mmhs->stat = m_hold;
  894.     port->mmhs->htype = 'N';
  895.   }
  896.  
  897. #ifdef MCH_AMIGA
  898. /* If there's only one call in the distribution list and that's who the
  899.    bulletin was received from, then mark the bulletin as forwarded
  900. */
  901.    if((port->mmhs->ext == 1) && (port->mmhs->count == 1)) {
  902.       if(port->mmhs->flag[0] == false)
  903.          port->mmhs->stat = m_fwd;
  904.    }
  905. #endif
  906.  
  907.   wt_mmhs();
  908.   makehdr2();
  909.  
  910.   if (*port->fld[port->flds-1] isnt '$') port->fld[port->flds-1] = nullstr;
  911.  
  912.   sprintf(port->line, "%u %-.6s@%-.6s %s %s", port->mmhs->number,
  913.    port->mmhs->to, port->mmhs->bbs, port->fld[port->flds-1], port->mmhs->title);
  914.  
  915.   log('M', port->opt1, port->opt2, port->line);
  916.   mfhs->next_msg++;
  917. #ifdef MCH_AMIGA
  918.    titles();
  919. #endif
  920. }
  921.  
  922. /*
  923.  *  Set up the beacon line.
  924.  */
  925.  
  926. setfwd()
  927. {
  928.   register char *cp, *lp;
  929.   register short i;
  930.  
  931. #ifdef MCH_AMIGA
  932.    all_number = 0;
  933.    gotmail = 0;
  934. #endif
  935.  
  936.   bldfwd();
  937. #ifndef MCH_AMIGA
  938.   if (ufwdm > 1)
  939.   {
  940.     strcpy(port->line, "BT Mail for:");
  941.     cp = ufwd;
  942.     lp = port->line + strlen(port->line);
  943. #else
  944. /* ufwdm > 1 is a bug. ufwdm is the MAX # of permitted callsigns.
  945.    It should be ufwdn > 0 which checks for actual number of callsigns.
  946.    I have also moved the strcpy and the alltnc() outside the 'if' 
  947.    so that the beacon text is changed if there is no mail. The problem
  948.    that can occur is that if there is currently one call in the btext
  949.    and then that mail is read, then there is now no call in the btext
  950.    but the original code doesn't change the BText to a null.
  951. */
  952.    strcpy(port->line, "BT Mail for:");
  953.     cp = ufwd;
  954.     lp = port->line + strlen(port->line);
  955.    if(ufwdn > 0) {
  956.       /* Does sysop have mail? */
  957.       for(i=0;i<ufwdn;i++) {
  958.          if(matchn(&ufwd[i*ln_call],cport->user->call,ln_call)) {
  959.             gotmail++;
  960.             break;
  961.          }
  962.       }
  963. #endif
  964.     while ((cp < ufwd + ln_call * ufwdn) and (lp < port->line + btmax))
  965.     {
  966.       *lp++ = ' ';
  967.       for (i = 0; i < ln_call; i++, cp++) if (*cp isnt ' ') *lp++ = *cp;
  968.     }
  969. #ifndef MCH_AMIGA
  970.     *lp++ = '\n';
  971.     *lp = '\0';
  972.     alltnc(port->line);
  973.   }
  974. #else
  975.    }
  976.    if(lp < port->line + btmax) {
  977.    /* If there's room, add ALL(N) on the end */
  978.       if(all_number) {
  979.          sprintf(tmpstr," ALL(%d)",all_number);
  980.          strcpy(lp,tmpstr);
  981.          lp += strlen(tmpstr);
  982.       }
  983.    }
  984. /* store LF at the end of the beacon command */
  985.    *lp++ = '\n';
  986.    *lp = '\0';
  987.    alltnc(port->line);
  988.    /* setfwd may find that sysop has mail so call titles just in case */
  989.    titles();
  990. #endif
  991. }
  992.  
  993. /*
  994.  *  General permission check: sysop or TO or FROM.
  995.  */
  996.  
  997. permit()
  998. {
  999.   if (port->mmhs->stat & (m_kill | m_busy)) return false;
  1000.   if (matchn(port->user->call, port->mmhs->to, ln_call) and
  1001.      !(port->mmhs->stat & m_hold)) return true;
  1002.   if (matchn(port->user->call, port->mmhs->from, ln_call)) return true;
  1003.   return false;
  1004. }
  1005.  
  1006. /*
  1007.  *  Return true if user has kill permission for current message.
  1008.  */
  1009.  
  1010. kpermit()
  1011. {
  1012.   if (port->mmhs->stat & m_kill) return false;
  1013.   if (port->mode & ops) return true;
  1014.   if (permit()) return true;
  1015.   return ((port->mmhs->type is 'T') and (port->opt2 is 'T'));
  1016. }
  1017.  
  1018. /*
  1019.  *  Return true if user has list permission for current message.
  1020.  */
  1021.  
  1022. lpermit()
  1023. {
  1024.   if (port->user->options & u_sysop) return true;
  1025.   if (permit()) return true;
  1026. #ifdef MCH_AMIGA
  1027. /* Users should be able to list a bulletin that has been forwarded.
  1028.    I did it this way, rather than remove the m_fwd from the final
  1029.    return statement, to avoid any unknown side-effects
  1030. */
  1031.    if((port->mmhs->type == 'B') && (port->mmhs->stat & m_fwd))return(true);
  1032. #endif
  1033.   return ((port->mmhs->type isnt 'P')
  1034.       and !(port->mmhs->stat & (m_fwd | m_kill | m_busy | m_hold)));
  1035. }
  1036.  
  1037. /*
  1038.  *  Return true if user has read permission for current message.
  1039.  */
  1040.  
  1041. rpermit()
  1042. {
  1043.   if ( port->mode & ops) return true;
  1044.   if (permit()) return true;
  1045.   return (port->mmhs->type isnt 'P');
  1046. }
  1047.  
  1048. /*
  1049.  *  Clean the mail file.
  1050.  *  Force drain of buffers, update of directory item.
  1051.  */
  1052.  
  1053. clnmsg()
  1054. {
  1055. #ifdef MCH_AMIGA
  1056.    lock_mail();
  1057. #endif
  1058.   close(mfl);
  1059.   mfl = open(mbfile, O_RDWR | O_BINARY);
  1060. #ifdef MCH_AMIGA
  1061.    unlock_mail();
  1062. #endif
  1063. }
  1064.  
  1065. /*
  1066.  *  Close the mail file.
  1067.  */
  1068.  
  1069. clsmsg()
  1070. {
  1071. #ifdef MCH_AMIGA
  1072.    if(mfl >= 0)
  1073. #endif
  1074.   close (mfl);
  1075. }
  1076.  
  1077. /*
  1078.  *  Open the mail file.
  1079.  */
  1080.  
  1081. opnmsg()
  1082. {
  1083.   register char *tp;
  1084.  
  1085. /*
  1086.  *  Allocate space for the mail file records.
  1087.  */
  1088.  
  1089.   mfhs  =  (MAIL_HDR *) malloc(sizeof(MAIL_HDR));
  1090.   tmmhs =  (MSG_HDR *)  malloc(sizeof(MSG_HDR));
  1091.  
  1092. /*
  1093.  *  Allocate the "who has mail" lists.
  1094.  */
  1095.  
  1096.   ufwd = (char *) malloc (ln_call * ufwdm);
  1097.   bfwd = (char *) malloc (ln_call * bfwdm);
  1098. #ifndef MCH_AMIGA
  1099.   if (bfwd is NULL) errall();
  1100. #else
  1101.   if (bfwd is NULL) errall(1);
  1102. #endif
  1103.  
  1104. /*
  1105.  *  Open the file. If it does not exist, make one.
  1106.  */
  1107.  
  1108. #ifdef MCH_AMIGA
  1109.    lock_mail();
  1110. #endif
  1111.   if ((mfl = open(mbfile, O_RDWR | O_BINARY)) < 0)
  1112.   {
  1113.     if ((mfl = open(mbfile, O_CREAT | O_RDWR | O_BINARY, pmode)) < 0)
  1114. #ifndef MCH_AMIGA
  1115.       { nofile(mbfile); exit(1); }
  1116. #else
  1117.       {
  1118.          nofile(mbfile);
  1119. #ifdef MCH_AMIGA
  1120.          unlock_mail();
  1121. #endif
  1122.          done(1);
  1123.       }
  1124. #endif
  1125.     inithdr();
  1126.     mfhs->next_msg = 1;
  1127. #ifdef MCH_AMIGA
  1128.    titles();
  1129. #endif
  1130.     write_rec(mfl, 0, (char *)mfhs);
  1131.   }
  1132.  
  1133. /*
  1134.  *  Read the mail file header.
  1135.  */
  1136.  
  1137.   read_rec(mfl, 0, (char *)mfhs);
  1138.  
  1139. #ifdef MCH_AMIGA
  1140.    unlock_mail();
  1141. #endif
  1142. /*
  1143.  *  If wrong version mail file, quit now.
  1144.  */
  1145.  
  1146.   if (mfhs->version isnt mb_version)
  1147.   {
  1148. #ifndef MCH_AMIGA
  1149.     printf("Expected version %d, got version %d\n",
  1150.       mb_version, mfhs->version);
  1151. #else
  1152.     sprintf(tmpstr,"Expected version %d, got version %d\n",
  1153.       mb_version, mfhs->version);
  1154.     ttputs(tmpstr);
  1155. #endif
  1156.     nofile(mbfile);
  1157. #ifndef MCH_AMIGA
  1158.     exit(1);
  1159. #else
  1160.    done(1);
  1161. #endif
  1162.   }
  1163.  
  1164. }
  1165.  
  1166. /*
  1167.  *  Initialize the mail file header.
  1168.  */
  1169.  
  1170. inithdr()
  1171. {
  1172. #ifdef MCH_AMIGA
  1173.    set_mail(1L);
  1174. #endif
  1175.   mfhs->next    = 1;
  1176.   mfhs->first   = 0;
  1177.   mfhs->last    = 0;
  1178.   mfhs->version = mb_version;
  1179.   mfhs->free    = 0;
  1180.   mfhs->count   = 0;
  1181.   mfhs->unt_msg = 1;
  1182.  
  1183. #ifdef MCH_AMIGA
  1184.    titles();
  1185. #endif
  1186.   curtim();
  1187.   strncpy(mfhs->date, l_date, ln_date);
  1188.   strncpy(mfhs->time, l_time, ln_time);
  1189.   fill(mfhs->unu, '\0', mfhsunu);
  1190. }
  1191.  
  1192. /*
  1193.  *  Open mail file and read first record.
  1194.  */
  1195.  
  1196. readmsg()
  1197. {
  1198. #ifdef MCH_AMIGA
  1199.    lock_mail();
  1200. #endif
  1201.   mfl = open(mbfile, O_RDWR | O_BINARY);
  1202.   read_rec(mfl, 0, (char *)mfhs);
  1203. #ifdef MCH_AMIGA
  1204.    unlock_mail();
  1205. #endif
  1206. }
  1207.  
  1208. /*
  1209.  *  Does this station want us to send BIDs ?
  1210.  */
  1211.  
  1212. isbid()
  1213. {
  1214.   register char *f;
  1215.  
  1216. /*  Is this a sid? It must have a '-' and end with a ']'  */
  1217.  
  1218.   if ((port->line[strlen(port->line) - 2] isnt ']' ) or
  1219.      ((f =  strrchr(port->line, '-')) is NULL))
  1220.      return;
  1221.  
  1222. #ifdef MCH_AMIGA
  1223. /* Look for THEBOX */
  1224.    if(matchn(&port->line[1],"THEBOX",6) ||
  1225.       matchn(&port->line[1],"DL5UY",5))
  1226.       thebox = 1;
  1227. /* Look for the newer KAM BBS which can handle BBS mail */
  1228. /* The KAM wouldn't need to be specifically recognized except that
  1229.    it only allows sending personal messages. So if someone sends
  1230.    a personal meesage to ALL @ ALLCAN it ought to be a bulletin.
  1231.    The program will change such personal messages to bulletins.
  1232. */
  1233.    if(matchn(&port->line[1],"KAM",3)) kambbs = 1;
  1234. #endif
  1235. /*  Look for special characters in the last field.  */
  1236.  
  1237.   f++;
  1238.   for (; *f isnt ']';f++)
  1239.   switch(*f)
  1240.   {
  1241.      case 'H' : s_mart setbit hidok; break;
  1242.      case '$' : s_mart setbit bidok; break;
  1243.  
  1244. #ifdef MCH_AMIGA
  1245.      case 'F' : s_mart setbit fbbok; break;
  1246.      case 'B' : s_mart setbit cmpok; break;
  1247.      case 'M' : s_mart setbit midok; break;
  1248. #ifdef MCH_ZOO
  1249. /* I was trying to get C-BBS to use the zoo compression routines instead of
  1250.    the lzhuf from FBB. But with no success so far.
  1251. */
  1252.      case 'Z' : s_mart setbit zoook; break;
  1253. #endif
  1254. #endif
  1255.  
  1256.  
  1257.   }
  1258. #ifdef MCH_AMIGA
  1259.    /* If both B and Z are set then Z overrides (Z is better) */
  1260.    if((s_mart & (cmpok|zoook)) == (cmpok|zoook)) {
  1261.       s_mart clrbit cmpok;
  1262.    }
  1263.  
  1264.    /* If FBB compression bit is set but FBB itself is not, then clear the
  1265.       compression
  1266.       If option #C is selected force the compression off anyway.
  1267.    */
  1268.    if((s_mart & (fbbok|cmpok)) == cmpok)s_mart clrbit cmpok;
  1269.    if(!optflags[2])s_mart clrbit cmpok;
  1270.  
  1271. #endif
  1272.  
  1273. }
  1274.  
  1275. /*
  1276.  *  Check to see whether we already have this BID.
  1277.  */
  1278.  
  1279. checkbid()
  1280. {
  1281.    FILE *out;
  1282.    char *a, *b;
  1283.  
  1284.    if(*port->mmhs->bid is ' ') {
  1285.       needbid = true;
  1286.       return;
  1287.    }
  1288. #ifdef MCH_AMIGA
  1289.    lock_bid();
  1290. #endif
  1291.    if((out = fopen(bidfile, "r")) is NULL) {
  1292. #ifdef MCH_AMIGA
  1293.       unlock_bid();
  1294. #endif
  1295.       nofile(bidfile); return; 
  1296.    }
  1297.    while(fgets(port->line, linelen, out) isnt NULL) {
  1298.  
  1299.     /* the first 4 characters are the date */
  1300.  
  1301.       strcpy(port->cmd, port->line + 4);
  1302.       a = port->cmd;
  1303.       remnl(a);
  1304.  
  1305.       a = port->line;
  1306.       b = port->mmhs->bid;
  1307.       unbl(a, b, ln_bid);
  1308.  
  1309.       if(match(port->cmd, port->line)) {
  1310.          needbid = false; 
  1311.          fclose(out);
  1312. #ifdef MCH_AMIGA
  1313.          unlock_bid();
  1314. #endif
  1315.          return;
  1316.       }
  1317.    }
  1318.    needbid = true;
  1319.    fclose(out);
  1320. #ifdef MCH_AMIGA
  1321.    unlock_bid();
  1322. #endif
  1323. }
  1324.  
  1325. putbid(y)
  1326. int y;
  1327. {
  1328.    FILE *out;
  1329.    char *a, *b;
  1330.  
  1331. #ifdef MCH_AMIGA
  1332.    lock_bid();
  1333. #endif
  1334.    if ((out = fopen(bidfile, "a")) is NULL)
  1335.    {
  1336. #ifdef MCH_AMIGA
  1337.    unlock_bid();
  1338. #endif
  1339.      port->msg = mcant; return;
  1340.    }
  1341.    a = port->cmd;
  1342.    if (y) b = port->mmhs->bid; else b = tmp->scr;
  1343.    unbl( a, b, ln_bid);
  1344.    sprintf (port->line, "%4.4s%s\n", port->mmhs->date+2, port->cmd);
  1345.    if (s_flag & s_dv) begin_lock();
  1346.    fputs(port->line, out);
  1347.    if (s_flag & s_dv) end_lock();
  1348.    fclose(out);
  1349. #ifdef MCH_AMIGA
  1350.    unlock_bid();
  1351. #endif
  1352. }
  1353.  
  1354.  
  1355. /****************************************
  1356.  *                                      *
  1357.  *  Code for the commands starts here   *
  1358.  *                                      *
  1359.  ****************************************/
  1360.  
  1361. /*
  1362.  *  GM or GR command: backup the mail file.
  1363.  */
  1364.  
  1365. untmsg()
  1366. {
  1367.   register word inhdr, me;
  1368.   if (port->opt2 isnt 'A') { if (sure()) return false; }
  1369.   if (!mfhs->count) { port->msg = mm[5]; return false; }
  1370.   prtx(mm[6]);
  1371.  
  1372.   close(mfl);         /*  Close current.  */
  1373.  
  1374.   unlink(mbbfile);    /*  Delete backup   */
  1375.  
  1376. /*
  1377.  *  Copy current to backup.
  1378.  */
  1379.  
  1380.   if (samedir(mbfile, mbbfile)) rename(mbfile, mbbfile);
  1381.   else copy(mbfile, mbbfile, false);
  1382.  
  1383.   unlink(mbfile);     /*  Delete current.  */
  1384.  
  1385. /*
  1386.  *  Open new current and backup.
  1387.  */
  1388.  
  1389.   mfl  = open(mbfile,  O_CREAT  | O_RDWR | O_BINARY, pmode);
  1390.   mflb = open(mbbfile, O_RDONLY | O_BINARY);
  1391.  
  1392.   read_rec(mflb, 0, (char *)mfhs);
  1393.   me = mfhs->last;
  1394.   inhdr = mfhs->first;
  1395.   inithdr();
  1396.  
  1397.   if (port->opt2 is 'R')
  1398.   {
  1399.     if (port->flds is 1) mfhs->next_msg = 1;
  1400.     else mfhs->next_msg = atoi(port->fld[1]);
  1401.   }
  1402.  
  1403.  
  1404.   while(inhdr <= me)        /*  For each message header ... */
  1405.   {
  1406.     read_rec(mflb, inhdr, (char *)port->mmhs); /* Read the header. */
  1407.  
  1408. /*
  1409.  *  Tell the sysop about this message.
  1410.  */
  1411.  
  1412.     sprintf(port->line, "%c %6u Size %6u # %6u Read %6u", port->mmhs->type,
  1413.       inhdr, port->mmhs->size, port->mmhs->number, port->mmhs->read);
  1414.     outstr(port->line);
  1415.  
  1416.     inhdr++;
  1417.  
  1418.     if (!(port->mmhs->stat & ( m_kill | m_busy)))
  1419.     {
  1420.        outstr("\n");
  1421.  
  1422. /*
  1423.  *  If renumbering messages, renumber this message.
  1424.  */
  1425.  
  1426.        if (port->opt2 is 'R')
  1427.        {
  1428.     msgfile(port->line, port->mmhs->number);
  1429.     msgfile(port->cmd,  mfhs->next_msg);
  1430.     rename(port->line, port->cmd);
  1431.     port->mmhs->number = mfhs->next_msg++;
  1432.        }
  1433.  
  1434. /*
  1435.  *  Write the header.
  1436.  */
  1437.  
  1438.        port->mmhs->rn = ++mfhs->count;
  1439.        wt_mmhs();
  1440.     }
  1441.     else arcmsg();
  1442.   }
  1443.  
  1444.  
  1445. /*
  1446.  *  Write the file header.
  1447.  */
  1448.   if (mfhs->count) mfhs->first = 1;
  1449.   mfhs->next = mfhs->count + 1;
  1450. #ifdef MCH_AMIGA
  1451.    set_mail((long)mfhs->next);
  1452. #endif
  1453.   mfhs->last = mfhs->count;
  1454.   mfhs->unt_msg = mfhs->next_msg;
  1455.   write_rec(mfl, 0, (char *)mfhs);
  1456.   close(mflb);
  1457.   clnmsg();
  1458. #ifdef MCH_AMIGA
  1459.    titles();
  1460. #endif
  1461.   return(true);
  1462. }
  1463.  
  1464.  
  1465. /*
  1466.  *  Print headers of unread messages for this user.
  1467.  */
  1468.  
  1469. newmsg()
  1470. {
  1471.   if (findfwd(port->user->call, ufwd, ufwdn) or
  1472.       findfwd(port->user->call, bfwd, bfwdn))
  1473.   {
  1474.     prtx(mm[2]);
  1475.     port->opt2 = '\0';
  1476.     port->flds = 1;
  1477.     lstmsg();
  1478.   }
  1479. }
  1480.  
  1481. /*
  1482.  *  L command, list messages.
  1483.  */
  1484.  
  1485. lstmsg()
  1486. {
  1487.   register short done, ok;
  1488.   word h, found, more, start;
  1489.   int max_title;
  1490. #ifdef MCH_AMIGA
  1491.    int quote;
  1492.    quote = 0;
  1493.    interflag = 0;
  1494. #endif
  1495.  
  1496.   if(port->mode & ops) max_title = false;
  1497.   else max_title = true;
  1498.  
  1499. /*
  1500.  *  First set up arguments.
  1501.  */
  1502.  
  1503.   found = 0; more = 0; done = false;
  1504. #ifndef MCH_AMIGA
  1505.   if ((*port->fld[1] is ';')or(*port->fld[2] is ';')or(*port->fld[3] is ';'))
  1506. #else
  1507. /* The ';' must be the last thing on the line if it is there.
  1508.    The previous argument can be a quoted string to do a search of
  1509.    the title of those articles that otherwise qualify.
  1510. */
  1511.    if(*port->fld[port->flds-1] is ';')
  1512. #endif
  1513.   { port->flds--; max_title = true; }
  1514.  
  1515. #ifdef MCH_AMIGA
  1516. /* If the last argument is a quoted string, remember where it is but
  1517.    pretend to remove it
  1518. */
  1519.    if(*port->fld[port->flds-1] is '"') {
  1520.       quote = --port->flds;
  1521.    }
  1522. #endif
  1523.  
  1524.   switch(port->opt2)
  1525.   {
  1526.     case '@' :
  1527.     case '<' :
  1528.     case '>' : pcall(tcall, port->fld[1]); break;
  1529.     case 'S' : if (port->flds is 1) {port->msg = mwhat; return;}
  1530.     case '\0': break;
  1531.     case 'E' :
  1532.     case ' ' : if (port->flds is 1) more = port->user->msg_number;
  1533.     default  :
  1534.       if (port->flds > 1)
  1535.       {
  1536.    if (!num(port->fld[1])) { port->msg = mwhat; return; }
  1537.    more = atoi(port->fld[1]);
  1538.       }
  1539.       if (port->flds is 3)
  1540.       {
  1541.    if (!num(port->fld[2])) { port->msg = mwhat; return; }
  1542.    start = atoi(port->fld[2]);
  1543.       }
  1544.   }
  1545.  
  1546. /*
  1547.  *  Log it, unless is initial login check for msgs.
  1548.  */
  1549.  
  1550.   if (port->opt2)
  1551.   {
  1552.     sprintf(port->line, "%u", more);
  1553.     log('M', 'L', port->opt2, port->line);
  1554.   }
  1555.  
  1556. /*
  1557.  *  Paw through the messages and show what requested.
  1558.  */
  1559.  
  1560. #ifdef MCH_AMIGA
  1561.    check_mail();
  1562.    unlock_mail();
  1563. #endif
  1564.   for (h = mfhs->last; h and !done; h--)
  1565.   {
  1566.     read_rec(mfl, h, (char *)port->mmhs);
  1567.     if ((port->opt2 is 'L') or ((port->opt2 is 'E') and (port->flds is 2)))
  1568.       done = (found is more); else done = (port->mmhs->number < more);
  1569.  
  1570.     ok = !done;
  1571.     if (port->flds is 3) if (ok)
  1572.       ok = (port->mmhs->number <= start);
  1573. /*
  1574.  *  Does this user have read permission for this message?
  1575.  */
  1576.  
  1577.     if (ok) ok = lpermit();
  1578.     if (ok) if (port->mmhs->stat & m_kill)
  1579.     ok=((port->opt2 is 'K')or(port->opt2 is 'E')or(port->opt2 is 'S'));
  1580.     if (ok) if (port->mmhs->stat & m_busy) ok = (port->opt2 is 'E');
  1581.  
  1582. /*
  1583.  *  Is this message wanted?
  1584.  */
  1585.  
  1586.     if (ok) switch(port->opt2)
  1587.     {
  1588.       case '\0': ok = matchn(port->user->call, port->mmhs->to, ln_call); break;
  1589.       case 'E' : break;
  1590.       case 'K' : ok = (port->mmhs->stat & m_kill); break;
  1591.       case 'F' : ok = (port->mmhs->stat & m_fwd);  break;
  1592.       case 'H' : ok = (port->mmhs->stat & m_hold); break;
  1593.       case 'L' : break;
  1594.       case 'M' : ok = matchn(port->user->call, port->mmhs->to, ln_call);
  1595.       if (!ok) ok = matchn(port->user->call, port->mmhs->from, ln_call);
  1596.       break;
  1597.  
  1598.       case 'O' : ok = (port->mmhs->stat & m_stale); break;
  1599. #ifdef MCH_AMIGA
  1600. /* Fix up strlen in 2 calls to search() .*/
  1601. #endif
  1602.       case 'S' : ok = (search(strupr(port->mmhs->title), port->fld[1],
  1603.             (short)strlen(port->fld[1]))or search(port->mmhs->to,
  1604.             port->fld[1],(short) strlen(port->fld[1]))); break;
  1605.       case 'U' : ok = !((port->mmhs->type is 'B')or(port->mmhs->type is 'A')
  1606.              or (port->mmhs->stat & (m_fwd | m_read))); break;
  1607.       case 'Y' : ok = (port->mmhs->stat & m_read);  break;
  1608. #ifndef MCH_AMIGA
  1609.       case '@' : ok = matchn(tcall, port->mmhs->bbs, ln_call); break;
  1610.       case '<' : ok = matchn(tcall, port->mmhs->from, ln_call); break;
  1611.       case '>' : ok = matchn(tcall, port->mmhs->to, ln_call); break;
  1612. #else
  1613. /* Permit a wildcard in these three forms of the 'L' command */
  1614. /* wmatch is in dir.c */
  1615.       case '@' : ok = wmatch(port->mmhs->bbs ,tcall); break;
  1616.       case '<' : ok = wmatch(port->mmhs->from,tcall); break;
  1617.       case '>' : ok = wmatch(port->mmhs->to  ,tcall); break;
  1618. #endif
  1619.       default  : ok = ((port->mmhs->type is port->opt2) or
  1620.              (port->opt2 is ' '));
  1621.     }
  1622. #ifdef MCH_AMIGA
  1623.    if(ok && quote) {
  1624.       /*
  1625.          If there was a quoted string in the argument list,
  1626.          check to see if it occurs in the title. If not,
  1627.          then ignore it. (umatch is in dir.c)
  1628.       */
  1629.       if(!umatch(&port->mmhs->title[0],port->fld[quote]))ok = 0;
  1630.    }
  1631.    if(interflag && (port != cport)) {
  1632.       return;
  1633.    }
  1634. #endif
  1635.     if (ok) if (prthdr(!found++, max_title) is 'Q') return;
  1636.   }
  1637.   if (!found) port->msg = mfind;
  1638.   s_flag setbit s_update;
  1639. }
  1640.  
  1641. /*
  1642.  *  CM command: duplicate a message.
  1643.  */
  1644.  
  1645. dupmsg()
  1646. {
  1647.   word tmpsize;
  1648.   if (!findmsg(atoi(port->fld[2]))) { port->msg = mnmsg; return; }
  1649.   port->opt1 = 'S';
  1650.  
  1651.   prthdr(true, true);
  1652.   pcall(port->mmhs->to, port->fld[1]);
  1653.   fill(port->mmhs->bbs, ' ', ln_call);
  1654.   port->mmhs->ext = 0;
  1655.  
  1656.   if (port->flds > 3) atfrom(port->flds - 2);
  1657.   if (port->flds > 5) atfrom(port->flds - 4);
  1658.   tmpsize = port->mmhs->size;
  1659.  
  1660. #ifdef MCH_AMIGA
  1661. /* Override @bbs if the user is on file */
  1662.    replace_bbs();
  1663. #endif
  1664.  
  1665.   msgfile(port->cmd, port->mmhs->number);
  1666.   initmsg(false);
  1667.   msgfile(port->line, mfhs->next_msg);
  1668.   copy(port->cmd, port->line, false);
  1669.   filesize = tmpsize;
  1670.   cremsg();
  1671. }
  1672.  
  1673. /*
  1674.  *  F command: copy a message to a file.
  1675.  */
  1676.  
  1677. filmsg()
  1678. {
  1679.   register char *p;
  1680.   register short hdr, append, inhdr;
  1681.   register FILE *out;
  1682.  
  1683.   if (!findmsg(atoi(port->fld[1]))) { port->msg = mnmsg; return; }
  1684.  
  1685.   hdr = true;
  1686.   append = false;
  1687.   inhdr = false;
  1688.  
  1689.   if (port->flds is 4) for (p = port->fld[3]; *p; p++) switch (*p)
  1690.   {
  1691.     case 'A' : append = true; break;
  1692.     case 'N' : hdr    = false; break;
  1693.     case 'I' : inhdr  = true; break;
  1694.     default: ;
  1695.   }
  1696.  
  1697.   if (port->opt2 is ' ') strcpy(port->line, port->fld[2]);
  1698.   else if (getdir(port->fld[2]) is NULL) { port->msg = mndir; return; }
  1699.  
  1700.   if (append) out = fopen (port->line, "a"); else
  1701.   {
  1702.     if ((out = fopen (port->line, "r")) isnt NULL)
  1703.       { fclose(out); port->msg = mexst; return; }
  1704.     out = fopen (port->line, "w");
  1705.   }
  1706.  
  1707.   if (out is NULL) { port->msg = mcant; return; }
  1708.  
  1709.   sprintf(tmp->scr, "%s %s", port->fld[1], port->line);
  1710.   log('M', 'D', port->opt2, tmp->scr);
  1711.  
  1712.   prthdr(true, true);
  1713.  
  1714.   if (hdr) fputs(tmp->scr, out);
  1715.  
  1716.   msgfile(port->cmd, port->mmhs->number);
  1717.  
  1718.   if ((port->fl = fopen(port->cmd, "r")) is NULL)
  1719.     { fclose(out); nofile(port->cmd); return; }
  1720.   fseek( port->fl, (long)RECSIZE, 0);
  1721.   while (fgets(tmp->scr, linelen, port->fl) isnt NULL)
  1722.   {
  1723.     if (!inhdr)
  1724.     {
  1725.       if (!parsehd(tmp->scr)) fputs(tmp->scr, out);
  1726.     }
  1727.     else
  1728.     fputs(tmp->scr, out);
  1729.   }
  1730.   fclose(port->fl);
  1731.   fclose(out);
  1732. }
  1733.  
  1734. /*
  1735.  *  Upload the message text file.
  1736.  */
  1737.  
  1738. uloadm(tname)
  1739. char *tname;
  1740. {
  1741.   register char *tp;
  1742.   register PORTS *p;
  1743.   short first, head;
  1744.   char *a, *b;
  1745. #ifdef MCH_AMIGA
  1746.    register int i;
  1747.    char orgcall[7];
  1748. #endif
  1749.   orgbbs[0] = '\0';
  1750.  
  1751.   p = port;
  1752.   if ((p->fl = fopen(tname, "w")) is NULL) { p->msg = mcant; return false; }
  1753.   fill(tmp->scr, '.', RECSIZE);
  1754.   tmp->scr[256] = '\0';
  1755.   fputs( tmp->scr, p->fl);
  1756.  
  1757.   first = true;
  1758.   head = true;
  1759.   filesize = 0;
  1760.   while (true)
  1761.   {
  1762.     while(!getdat());
  1763.  
  1764. /*
  1765.  *  If user disconnected, timed out, or forced off, zap the file.
  1766.  */
  1767.  
  1768.     if (p->mode & gone)
  1769.     {
  1770.       fclose(p->fl);
  1771.       return false;
  1772.     }
  1773.  
  1774.     if (head)
  1775.     {
  1776.       if (!parsehd(p->line)) head = false;
  1777.       else
  1778.  
  1779. /*  If this is a ping-pong message */
  1780.       if (s_param & s_ping)
  1781.       {
  1782.    a = p->cmd;
  1783.    b = cport->user->call;
  1784.    unbl(a, b, 6);
  1785.    if (matchn(orgbbs, p->cmd, ln_call))
  1786.    {
  1787.      holdit = true;
  1788.      port->mmhs->htype = 'P';
  1789.    }
  1790.       }
  1791. #ifdef MCH_AMIGA
  1792. /* Check each R: line in the bulletin header. If the BBS call is in our
  1793.    distribution list for this bulletin, then mark them as already having
  1794.    received the bulletin.
  1795. */
  1796.       if(head && p->mmhs->ext == 1) {
  1797.          pcall(orgcall,orgbbs);
  1798.          for(i = 0;i < p->mmhs->count; i++) {
  1799.             if(p->mmhs->flag[i]) {
  1800.                if(matchn(orgcall,p->mmhs->call[i],ln_call)) {
  1801.                   p->mmhs->flag[i] = false;
  1802.                   break;
  1803.                }
  1804.             }
  1805.          }
  1806.       }
  1807. #endif
  1808.     }
  1809. /*
  1810.  *  If the first line is not a header (thus it is a human entering
  1811.  *  the message), make sure there is an initial blank line before
  1812.  *  the body of the message.
  1813.  */
  1814.  
  1815.     if (first)
  1816.     {
  1817.       first = false;
  1818.       if (*orgbbs is '\0') if (*p->line isnt '\n') fputs("\n", p->fl);
  1819.     }
  1820.  
  1821. /*
  1822.  *  Stuff the line into the file.
  1823.  */
  1824.  
  1825.     if (match(p->line, "/EX\n") or match(p->line,"/ex\n"))
  1826.     {
  1827.       fclose(p->fl);
  1828.       return true;
  1829.     }
  1830.  
  1831.  
  1832.     if ((tp = strchr(p->line, cpmeof)) is NULL)
  1833.     {
  1834.       filesize += strlen(p->line);
  1835.       fputs(p->line, p->fl);
  1836.     }
  1837.     else
  1838.     {
  1839.       if (tp isnt p->line)
  1840.       {
  1841.          *tp++ = '\n';
  1842.          *tp   = '\0';
  1843.          filesize += strlen(p->line);
  1844.          fputs(p->line, p->fl);
  1845.       }
  1846.       fclose(p->fl);
  1847.       return true;
  1848.     }
  1849.   }
  1850. }
  1851.  
  1852. /*
  1853.  *  "Display the message text" utility.
  1854.  */
  1855.  
  1856. dloadm(sh)
  1857. short sh;
  1858. {
  1859.   short first;
  1860.  
  1861.   sprintf(port->line, "%u", port->mmhs->number);
  1862.   log('M', 'R', port->opt2, port->line);
  1863.   port->mmhs->read++;
  1864.   if (matchn(port->user->call, port->mmhs->to, ln_call))
  1865.     port->mmhs->stat setbit m_read;
  1866.   if (port->mmhs->ext is 1)
  1867.   if (matchn(port->user->call, port->mmhs->call[0], ln_call))
  1868.   {
  1869.     markdis(0);
  1870.     port->mmhs->stat clrbit m_hold;
  1871.   }
  1872.   wt_mmhs();
  1873.   makehdr2();
  1874.   prthdr(true, true);
  1875.  
  1876.   msgfile(port->line, port->mmhs->number);
  1877.  
  1878.   if ((port->fl = fopen(port->line, "r")) is NULL)
  1879.     { nofile(port->line); return; }
  1880.  
  1881. #ifdef MCH_AMIGA
  1882.  
  1883. /* Code to save the information that will allow the Send Reply command
  1884.    to construct a proper reply to this message. At the moment a reply
  1885.    is permitted only for personal messages addressed to the reader.
  1886.    (I'm not sure that this test is needed, but play it safe).
  1887.    REMOVED until I have the SR command working properly.
  1888. */
  1889. #ifdef MCH_SR
  1890.    if(port->mmhs->type == 'P') {
  1891.                    /* matchn(port->user->call,port->mmhs->to,ln_call)) { */
  1892.       last_msg.type = 'P';
  1893.       unbl(last_msg.from,port->mmhs->from,ln_call);
  1894.       unbl(last_msg.bbs,port->mmhs->bbs,ln_call);
  1895.       strncpy(last_msg.title,port->mmhs->title,mhtitl);
  1896.    }
  1897.    else last_msg.type = 0;
  1898. #else
  1899.    last_msg.type = 0;
  1900. #endif
  1901.  
  1902.    /* Start the line counter */
  1903.    pgst(NULL);
  1904. #endif
  1905.  
  1906.   fseek( port->fl, (long)RECSIZE, 0 );
  1907.   pgck();   /* First line of header */
  1908.   pgck();   /* Second line of header */
  1909.   pgck();   /* Path line */
  1910.   if (port->mmhs->ext) pgck();
  1911.   if (*port->mmhs->bid isnt ' ') pgck();
  1912.  
  1913.   strcpy(tmp->scr, "  Path: ");
  1914.   first = true;
  1915.  
  1916. #ifdef MCH_AMIGA
  1917.    interflag = 0;
  1918. #endif
  1919.  
  1920.   while(fgets(port->line, linelen, port->fl) isnt NULL)
  1921.   {
  1922.  
  1923. #ifdef MCH_AMIGA
  1924.    if(interflag && (port != cport)) {
  1925.       break;
  1926.    }
  1927. #endif
  1928.  
  1929.     if (!sh)
  1930.     {
  1931.       sh = !parsehd(port->line);
  1932.       if (sh)
  1933.       {
  1934.    if (!first)
  1935.    {
  1936.      strcat(tmp->scr, "\n\n");
  1937.      outstr(tmp->scr);
  1938.      pgck();
  1939.      prtx("Date: $j/$k\n");  pgck();
  1940.      prtx("From: $P @ $a\n");  pgck();
  1941.      prtx("Message-Id: <$m@$a>\n");  pgck();
  1942.      prtx("To: $G @ ");
  1943.      if (*port->mmhs->bbs is ' ')  prtx("$O\n");
  1944.      else if (port->mmhs->ext is 2) prtx("$h\n");
  1945.      else prtx("$A\n");  pgck();
  1946.      prtx("Subject: $E\n\n");  pgck();
  1947.    }
  1948.       }
  1949.       else
  1950.       {
  1951.    if (!first) strcat(tmp->scr, "!");
  1952.    strcat(tmp->scr, orgbbs);   
  1953.    first = false;
  1954.       }
  1955.     }
  1956.  
  1957.     if (sh)
  1958.     {
  1959.       outstr(port->line);
  1960.       if (lstquit()) { fclose(port->fl); return; }
  1961.     }
  1962.   }
  1963.   fclose (port->fl);
  1964. }
  1965.  
  1966. /*
  1967.  *  RM command: read my messages.
  1968.  */
  1969.  
  1970. rdmsgm()
  1971. {
  1972.   register short found;
  1973.   register word h;
  1974.  
  1975.   found = false;
  1976. #ifdef MCH_AMIGA
  1977.    check_mail();
  1978.    unlock_mail();
  1979. #endif
  1980.   for (h = mfhs->first; h and h <= mfhs->last; h++)
  1981.   {
  1982.     read_rec(mfl, h, (char *)port->mmhs);
  1983.     if ((!(port->mmhs->stat & (m_read|m_kill|m_fwd|m_hold|m_busy)) and
  1984.       (matchn(port->user->call, port->mmhs->to, ln_call))) or
  1985.       (!(port->mmhs->stat & (m_read|m_kill|m_fwd|m_busy)) and
  1986.       (port->mmhs->ext is 1) and
  1987.       matchn(port->user->call, port->mmhs->call[0], ln_call) and
  1988.       port->mmhs->flag[0]))
  1989.     {
  1990.       dloadm(port->mode & ops);
  1991.       found = true;
  1992.       if (pause() is 'Q') return;
  1993.     }
  1994.   }
  1995.   if (!found) port->msg = mfind;
  1996. }
  1997.  
  1998. /*
  1999.  *  R command: read one message.
  2000.  */
  2001.  
  2002. rdmsg()
  2003. {
  2004.   char sn[6];
  2005.   if ((strlen(port->fld[1]) > 5) or (!num(port->fld[1])))
  2006.   {
  2007.      port->msg = mwhat;
  2008.      return;
  2009.   }
  2010.   strcpy(sn, port->fld[1]);
  2011.   if (!findmsg(atoi(port->fld[1]))) { port->msg = mnmsg; return; }
  2012.   if (!rpermit())                   { port->msg = mprot; return; }
  2013.  
  2014.   dloadm(port->opt2 is 'H');
  2015.   if ((port->mmhs->type is 'T')and(!(port->mmhs->stat&(m_busy|m_kill|m_fwd))))
  2016.   {
  2017.     outstr("\nAre you going to deliver this message (Y/N)?\n");
  2018.     while (!getdat());
  2019.     if(toupper(*port->line) is 'Y')
  2020.     {
  2021.       port->opt2 = 'T';
  2022.       strcpy(port->fld[1], sn);
  2023.       sprintf(port->line, "KT %s\n", sn);
  2024.       outstr(port->line);
  2025.       klmsg();
  2026.     }
  2027.   }
  2028. }
  2029.  
  2030. /*
  2031.  *  KF, KM, KO, KY, KK commands, kill multiple messages.
  2032.  */
  2033.  
  2034. klmsgm()
  2035. {
  2036.   register short ok;
  2037.   register short found;
  2038.   word h, next;
  2039.     if (port->flds is 2) pcall(tcall, port->fld[1]);
  2040.  
  2041. #ifdef MCH_AMIGA
  2042.    check_mail();
  2043.    unlock_mail();
  2044. #endif
  2045.     found = false;
  2046.     for (h = mfhs->first; h and h <= mfhs->last; h++)
  2047.     {
  2048.       read_rec(mfl, h, (char *)port->mmhs);
  2049.  
  2050.       ok = kpermit();
  2051.       if (ok) ok = !(port->mmhs->stat & m_hold);
  2052.  
  2053.       if (ok) if (port->flds is 2) ok = matchn(tcall, port->mmhs->to, ln_call);
  2054.  
  2055.       if (ok) switch(port->opt2)
  2056.       {
  2057.    case 'F' : ok = (port->mmhs->stat & m_fwd); break;
  2058.    case 'M' :
  2059.        ok = ((port->mmhs->stat & m_read) and
  2060.        matchn(port->user->call, port->mmhs->to, ln_call));
  2061.        break;
  2062.    case 'O' : ok = (port->mmhs->stat & m_stale); break;
  2063.    case 'Y' : ok = (port->mmhs->stat & m_read);  break;
  2064.       }
  2065.  
  2066.       if (ok)
  2067.       {
  2068.    sprintf(port->line, "%u", port->mmhs->number);
  2069.    log('M', 'K', port->opt2, port->line);
  2070.    prtx(mm[7]);
  2071.    found = true;
  2072.    port->mmhs->stat setbit m_kill;
  2073.    write_rec(mfl, port->mmhs->rn, (char *)port->mmhs);
  2074.    makehdr2();
  2075.       }
  2076.     }
  2077. #ifdef MCH_AMIGA
  2078.    titles();
  2079. #endif
  2080.     if (!found) port->msg = mfind;
  2081. }
  2082.  
  2083. klmult()
  2084. {
  2085.   mult(false);
  2086. }
  2087.  
  2088. rdmult()
  2089. {
  2090.   mult(true);
  2091. }
  2092.  
  2093. /*
  2094.  *  Handling multiple messages.
  2095.  */
  2096.  
  2097. mult(x)
  2098. int x;
  2099. {
  2100.   static char msgn[25];
  2101.   int i;
  2102.  
  2103.   strncpy(&msgn[0], port->fld[2], 5);
  2104.   strncpy(&msgn[6], port->fld[3], 5);
  2105.   strncpy(&msgn[12], port->fld[4], 5);
  2106.   strncpy(&msgn[18], port->fld[5], 5);
  2107.   if (x) rdmsg();
  2108.   else
  2109.   {
  2110.     outstr(port->fld[1]);
  2111.     klmsg();
  2112.   }
  2113.     prtx(port->msg);
  2114.   for ( i=0; msgn[i]; i += 6)
  2115.   {
  2116.     strcpy(port->fld[1], &msgn[i]);
  2117.     if (x) rdmsg();
  2118.     else
  2119.     {
  2120.       outstr(port->fld[1]);
  2121.       klmsg();
  2122.     }
  2123.     prtx(port->msg);
  2124.     port->msg = NULL;
  2125.   }
  2126. }
  2127.  
  2128. /*
  2129.  *  K command, kill a message.
  2130.  */
  2131.  
  2132. klmsg()
  2133. {
  2134.   register short dosvc;
  2135.   unsigned int org_num;
  2136.  
  2137.   if (!num(port->fld[1]))           { port->msg = mwhat; return; }
  2138.   if (!findmsg(atoi(port->fld[1]))) { port->msg = mnmsg; return; }
  2139.   if (port->mmhs->stat & m_kill)    { port->msg = mnmsg; return; }
  2140.   if (!kpermit())                   { port->msg = mprot; return; }
  2141.  
  2142.   log('M', 'K', port->opt2, port->fld[1]);
  2143.  
  2144.   dosvc = (port->opt2 is 'T') and
  2145.      (port->mmhs->type is 'T') and
  2146.      (s_param & s_svc);
  2147.  
  2148.   if (dosvc) org_num = atoi(port->fld[1]);
  2149.  
  2150. /*
  2151.  *  Marked the message as  Killed.
  2152.  */
  2153.  
  2154.   if(port->opt2 is 'A') port->mmhs->stat setbit m_noarc;
  2155.   port->mmhs->stat setbit m_kill;
  2156.   write_rec(mfl, port->mmhs->rn, (char *)port->mmhs);
  2157.   makehdr2();
  2158.  
  2159. /*
  2160.  *  If this is KT of T type message, and we do service messages,
  2161.  *  do the service message.
  2162.  */
  2163.  
  2164.   if (dosvc)
  2165.   {
  2166.     port->mmhs->ext = 0;
  2167.     findat();
  2168.     port->opt1 = 'S';
  2169.     strncpy(port->mmhs->to, port->mmhs->from, ln_call);
  2170.     strncpy(port->mmhs->from, cport->user->call, ln_call);
  2171.     port->mmhs->type = 'P';
  2172.     fill(port->mmhs->bid, ' ', ln_bid);
  2173.     initmsg(false);
  2174.     msgfile(port->line, mfhs->next_msg);
  2175.     port->fl = fopen(port->line, "w");
  2176.     fseek(port->fl, (long)RECSIZE, 0);
  2177.     fprintf(port->fl, "Msg %5u taken from %6.6s by %6.6s at %4.4s on %6.6s\n",
  2178.       org_num, cport->user->call, port->user->call, l_time, l_date);
  2179.     fclose(port->fl);
  2180.  
  2181.     filesize = 56;
  2182.     cremsg();
  2183.   }
  2184.   port->msg = mdone;
  2185. #ifdef MCH_AMIGA
  2186.    titles();
  2187. #endif
  2188. }
  2189.  
  2190. /*
  2191.  *  S command: send a message.
  2192.  */
  2193.  
  2194. sndmsg()
  2195. {
  2196.   char *a, *b;
  2197.  
  2198.   holdit = false;   /* initialize it to something */
  2199. #ifndef MCH_AMIGA
  2200.   pfld();
  2201. #else
  2202.    if(srcmd_flag == 0)last_msg.type = 0;
  2203. /* If there's an error in the command then return */
  2204.    if(pfld() == 0)return;
  2205.  
  2206. /* Initialize ->ext to zero so that dodis() will detect that sndmsg has
  2207.    already done it and then cremsg won't redo it. This is so that the
  2208.    uloadm routine can use parsehd() to see if an incoming bulletin has
  2209.    already been seen by other BBS in the distribution list and then we
  2210.    won't have to send it to them.
  2211.    The only other call to dodis() previously sets ->ext to zero.
  2212. */
  2213.    if(port->mmhs->ext != 2)port->mmhs->ext = 0;
  2214.    dodis();
  2215. #endif
  2216.  
  2217.   if (!isalnum(*port->mmhs->to))
  2218.   {
  2219.     holdit = true;
  2220.     port->mmhs->htype = 'C';
  2221.   }
  2222.   if (port->mode & gone) return;
  2223.  
  2224.   if (s_mart) {
  2225.     if (!needbid) return;
  2226.   }
  2227.   else {
  2228.     if (port->user->options & (u_bbs | u_expert))
  2229.     outstr("Msg:\n");
  2230.     else prtx(mm[1]);
  2231.   }
  2232.  
  2233.   msgfile(port->cmd, mfhs->next_msg);
  2234.   if (!uloadm(port->cmd)) return;
  2235.  
  2236. /*
  2237.  *  If this is a Bulletin and has no BID, 
  2238.  *  parse the headers and give it one.
  2239.  */
  2240. #ifndef MCH_AMIGA
  2241.   if (!iscall(port->mmhs->to))
  2242.   if (port->mmhs->type is 'B')
  2243.   {
  2244. #else
  2245. /* Add BID or a MID to any kind of message */
  2246.   if(*port->mmhs->bid == ' ') {
  2247.    unbl(port->line, cport->user->call, ln_call);
  2248. #endif
  2249.    a = port->line;
  2250.    b = cport->user->call;
  2251.    unbl(a, b, 6);
  2252.  
  2253. /* Default the BID as to coming from this BBS with our msg number. */
  2254.  
  2255.    sprintf(tmp->scr, "%-u_%-s", mfhs->next_msg, port->line);
  2256.  
  2257. /* Now check the parsed headers if it came from another BBS. */
  2258.  
  2259.    if (*orgbbs isnt '\0') sprintf(tmp->scr, "%s_%s", orgmsg, orgbbs);
  2260.  
  2261.    if (!hasbid)
  2262.    {
  2263.       strncpy(port->mmhs->bid, tmp->scr, ln_bid);
  2264.       hasbid = true;
  2265.    }
  2266.    else if (!matchn(port->mmhs->bid, tmp->scr, ln_bid)) putbid(false);
  2267.  
  2268.    if (port->user->options & u_hold)
  2269.    {
  2270.      holdit = true;
  2271.      port->mmhs->htype = 'U';
  2272.    }
  2273.   }
  2274.   checkbid(); 
  2275.   if (!needbid)
  2276.   {
  2277.     holdit = true;
  2278.     port->mmhs->htype = 'D';
  2279.   }
  2280.   cremsg();
  2281. }
  2282.  
  2283. /*
  2284.  *  SM command, send a message to a distribution list.
  2285.  */
  2286.  
  2287. sndmlt()
  2288. {
  2289.   register FILE *fl;
  2290.   char fn[80];
  2291.   register short first = true;
  2292.   word tmpsize;
  2293.   
  2294.   holdit = false;
  2295.   fill(port->mmhs->bid, ' ', ln_bid);
  2296.  
  2297.   if ((fl = fopen(port->fld[1], "r")) is NULL)
  2298.     { nofile(port->fld[1]); return; }
  2299.  
  2300.   prtx(mm[0]);
  2301.   get_title();
  2302.   if (port->mode & gone) { fclose(fl); return; }
  2303.  
  2304.   if (port->flds is 3) if (*port->fld[port->flds-1] is '$')
  2305.   {
  2306. /* MCH_AMIGA */
  2307.     if (*(port->fld[port->flds-1] + 1) /*isnt NULL*/)
  2308.     {
  2309.       strncpy(port->mmhs->bid, port->fld[port->flds-1] + 1, ln_bid);
  2310.       hasbid = true;
  2311.     }
  2312.   }
  2313.  
  2314.   prtx(mm[1]);
  2315.  
  2316.   strncpy(port->mmhs->from, port->user->call, ln_call);
  2317.   port->mmhs->ext = 0;
  2318.   initmsg(false);
  2319.   msgfile(fn, mfhs->next_msg);
  2320.   if (!uloadm(fn)) { fclose(fl); return; }
  2321.   tmpsize = filesize;
  2322.  
  2323.   while (fgets(port->line, linelen, fl) isnt NULL)
  2324.   {
  2325.     parse();
  2326.     if (!first)
  2327.     {
  2328.       port->mmhs->ext = 0;
  2329.       initmsg(false);
  2330.       msgfile(port->line, mfhs->next_msg);
  2331.       copy(fn, port->line, false);
  2332.     }
  2333.     port->mmhs->type = port->opt2;
  2334.     pcall(port->mmhs->to, port->fld[1]);
  2335.     fill(port->mmhs->bbs, ' ', ln_call);
  2336.  
  2337.     if(port->flds > 3) atfrom(2);
  2338.     if(port->flds > 5) atfrom(4);
  2339.     filesize = tmpsize;
  2340. #ifdef MCH_AMIGA
  2341.    replace_bbs();
  2342. /* Put a BID or MID on this file if needed */
  2343.    if( (port->mmhs->type is 'B') || (port->mmhs->type == 'P'))  {
  2344.       unbl(port->line, cport->user->call, ln_call);
  2345.  
  2346.       /* Default the BID as to coming from this BBS with our msg number. */
  2347.  
  2348.       sprintf(tmp->scr, "%-u_%-s", mfhs->next_msg, port->line);
  2349.       strncpy(port->mmhs->bid, tmp->scr, ln_bid);
  2350.       hasbid = true;
  2351.    }
  2352. #endif
  2353.     cremsg();
  2354.     first = false;
  2355.   }
  2356.   fclose(fl);
  2357. }
  2358.  
  2359. /*
  2360.  *  M command, make a message from a file.
  2361.  */
  2362.  
  2363. makmsg()
  2364. {
  2365. #ifdef MCH_AMIGA
  2366.    char *a,*b;
  2367. #endif
  2368.   if ((port->fl = fopen(port->fld[2], "r")) is NULL)
  2369.     { nofile(port->fld[2]); return; }
  2370.   fclose(port->fl);
  2371. #ifndef MCH_AMIGA
  2372.   pfld();
  2373. #else
  2374. /* If there's an error in the command then return */
  2375.    if(pfld() == 0)return;
  2376. #endif
  2377.   if (port->mode & gone) return;
  2378. #ifdef MCH_AMIGA
  2379. /* Put a BID or MID on this file if needed */
  2380.    if( (port->mmhs->type is 'B') || (port->mmhs->type == 'P'))  {
  2381.       unbl(port->line, cport->user->call, ln_call);
  2382.  
  2383.       /* Default the BID as coming from this BBS with our msg number. */
  2384.  
  2385.       sprintf(tmp->scr, "%-u_%-s", mfhs->next_msg, port->line);
  2386.       strncpy(port->mmhs->bid, tmp->scr, ln_bid);
  2387.       hasbid = true;
  2388.    }
  2389. #endif
  2390.   msgfile(port->line, mfhs->next_msg);
  2391.   copy(port->fld[2], port->line, true);
  2392.   cremsg();
  2393. }
  2394.  
  2395. /*
  2396.  *  MM command, make multiple messages from a file.
  2397.  */
  2398.  
  2399. makmlt()
  2400. {
  2401.   register FILE *dfl;
  2402.   char tnm[80];
  2403.  
  2404.   holdit = false;
  2405.   fill(port->mmhs->bid, ' ', ln_bid);
  2406.  
  2407.   if ((port->fl = fopen(port->fld[2], "r")) is NULL)
  2408.     { nofile(port->fld[2]); return; }
  2409.   fclose(port->fl);
  2410.  
  2411.   if ((dfl = fopen(port->fld[1], "r")) is NULL)
  2412.     { nofile(port->fld[1]); return; }
  2413.  
  2414.   strcpy(tnm, port->fld[2]);
  2415.  
  2416.   if (port->flds is 4) if (*port->fld[port->flds-1] is '$')
  2417.   {
  2418. /* MCH_AMIGA */
  2419.     if (*(port->fld[port->flds - 1] + 1)/* isnt NULL*/)
  2420.     {
  2421.       strncpy(port->mmhs->bid, port->fld[port->flds-1] + 1, ln_bid);
  2422.       hasbid = true;
  2423.     }
  2424.   }
  2425.  
  2426.   prtx(mm[0]);
  2427.   get_title();
  2428.   if (port->mode & gone) { fclose(dfl); return; }
  2429.  
  2430.   while (fgets(port->line, linelen, dfl) isnt NULL)
  2431.   {
  2432.     parse();
  2433.     port->mmhs->type = port->opt2;
  2434.     pcall(port->mmhs->to, port->fld[1]);
  2435.     strncpy(port->mmhs->from, port->user->call, ln_call);
  2436.     fill(port->mmhs->bbs, ' ', ln_call);
  2437.     port->mmhs->ext = 0;
  2438.  
  2439.     if (port->flds > 3) atfrom(2);
  2440.     if (port->flds > 5) atfrom(4);
  2441. #ifdef MCH_AMIGA
  2442. /* Put a BID or MID on this file if needed */
  2443.    if( (port->mmhs->type is 'B') || (port->mmhs->type == 'P'))  {
  2444.       unbl(port->line, cport->user->call, ln_call);
  2445.  
  2446.       /* Default the BID as to coming from this BBS with our msg number. */
  2447.  
  2448.       sprintf(tmp->scr, "%-u_%-s", mfhs->next_msg, port->line);
  2449.       strncpy(port->mmhs->bid, tmp->scr, ln_bid);
  2450.       hasbid = true;
  2451.    }
  2452.     replace_bbs();
  2453. #endif
  2454.     initmsg(false);
  2455.     msgfile(port->line, mfhs->next_msg);
  2456.     copy(tnm, port->line, true);
  2457.     cremsg();
  2458.   }
  2459.   fclose(dfl);
  2460. }
  2461.  
  2462. /*
  2463.  *  Mark stale messages.
  2464.  */
  2465.  
  2466. stale()
  2467. {
  2468.   register word i;
  2469.   register int ks;
  2470.   register short ts;
  2471.  
  2472.   for (i = mfhs->first; i and i <= mfhs->last; i++)
  2473.   {
  2474.     read_rec(mfl, i, (char *)port->mmhs);
  2475.  
  2476.     switch(port->mmhs->type)
  2477.     {
  2478.       case 'T': ts = tstalen; ks = (s_flag & s_nkill); break;
  2479.       case 'P': ts = tstaleu; ks = (s_flag & s_ukill); break;
  2480.       default :
  2481.       {
  2482.    ts = tstaleb; ks = (s_flag & s_bkill);          /* Max time period */
  2483. #ifdef MCH_AMIGA
  2484.    /* If this is a bulletin and the lifetime is less than the default
  2485.       then use the lifetime
  2486.    */
  2487.     if(port->mmhs->type is 'B') {
  2488.        if(port->mmhs->lifetime && (port->mmhs->lifetime < ts)) {
  2489.           ts = port->mmhs->lifetime;
  2490.        }
  2491.     }
  2492. #endif
  2493.    if (!(port->mmhs->stat & m_bull))
  2494.    {
  2495.      if (ddiff(port->mmhs->date, l_date, true) > tstale1)  /* 1st time period */
  2496.        if (port->mmhs->read < rstale1) ts = 0;
  2497.      if (ddiff(port->mmhs->date, l_date, true) > tstale2)  /* 2nd time period */
  2498.        if (port->mmhs->read < rstale2) ts = 0;
  2499.      if (ddiff(port->mmhs->date, l_date, true) > tstale3)  /* 3rd time period */
  2500.        if (port->mmhs->read < rstale3) ts = 0;
  2501.    }
  2502.       }
  2503.     }
  2504.  
  2505.     if (!(port->mmhs->stat & m_stale))
  2506.     if (ddiff(port->mmhs->date, l_date, true) > ts)
  2507.     {
  2508.       if (ks and !(port->mmhs->stat & m_hold)) port->mmhs->stat setbit m_kill;
  2509.       else port->mmhs->stat setbit m_stale;
  2510.       write_rec(mfl, i, (char *)port->mmhs);
  2511.     }
  2512.   }
  2513. }
  2514.  
  2515. /*
  2516.  *  DW command: make wp message from user file.
  2517.  */
  2518.  
  2519. dwuser()
  2520. {
  2521.   register int i;
  2522.   register short first = true;
  2523.   short doall;
  2524.  
  2525.   if (*wpcall is ' ') return;
  2526.  
  2527.   doall = port->flds is 2;
  2528.   port->opt1 = 'S';
  2529.   port->opt2 = 'P';
  2530.   filesize = 0;
  2531. #ifdef MCH_AMIGA
  2532.    check_user();
  2533.    unlock_user();
  2534. #endif
  2535.  
  2536.   for (i = 1; i <= ufhs->count; i++)
  2537.   {
  2538.     read_rec(ufl, i, (char *)tuser);
  2539.     if ((tuser->state & u_home) and (tuser->state & u_zip))
  2540.     if (doall or !(tuser->state & u_sent))
  2541.     {
  2542.       if (first)
  2543.       {
  2544.    first = false;
  2545.    port->mmhs->type = 'P';
  2546.    strncpy(port->mmhs->to, "WP    ", ln_call);
  2547.    strncpy(port->mmhs->from, cport->user->call, ln_call);
  2548.    strncpy(port->mmhs->bbs, wpcall, ln_call);
  2549.    strcpy(port->mmhs->title, "WP Update");
  2550.    fill(port->mmhs->bid, ' ', ln_bid);
  2551.    port->mmhs->ext = 0;
  2552.    initmsg(false);
  2553.    msgfile(port->line, mfhs->next_msg);
  2554.    port->fl = fopen(port->line, "w");
  2555.    fseek(port->fl, (long)RECSIZE, 0);
  2556.       }
  2557.  
  2558.       filesize += 72;
  2559.       fprintf(port->fl, "On %6.6s %6.6s @ %6.6s zip %6.6s %-12.12s %-20.20s\n",
  2560.       tuser->date, tuser->call, tuser->home_bbs, tuser->zip,
  2561.       tuser->handle, tuser->qth);
  2562.  
  2563.       tuser->state setbit u_sent;
  2564.       if (s_flag & s_dv) begin_lock();
  2565.       write_rec(ufl, i, (char *)tuser);
  2566.       if (s_flag & s_dv)end_lock();
  2567.       if (i is port->user->rn) port->user->state setbit u_sent;
  2568.     }
  2569.   }
  2570.  
  2571.   if (!first)
  2572.   {
  2573.     fclose(port->fl);
  2574.     chkhier();
  2575.     cremsg();
  2576.   }
  2577. }
  2578.  
  2579. /*
  2580.  *  E command, edit a message header.
  2581.  */
  2582.  
  2583. edmsg()
  2584. {
  2585.   FILE *out;
  2586.   char *a, *b;
  2587. #ifdef MCH_AMIGA
  2588.    short life;
  2589. #endif
  2590.  
  2591.   if (!findmsg(atoi(port->fld[1]))) { port->msg = mnmsg; return; }
  2592.   while (*port->fld[0] isnt '\0')
  2593.   {
  2594.     prthdr(true, true);
  2595. #ifdef MCH_AMIGA
  2596.     if(port->mmhs->type == 'B')
  2597.   outstr("t(Y)pe, (S)tatus, (T)o, (F)rom, (B)bs, t(I)tle, bi(D), (L)ifetime\n");
  2598.    else
  2599. #endif
  2600.     outstr("t(Y)pe, (S)tatus, (T)o, (F)rom, (B)bs, t(I)tle, bi(D)\n");
  2601.     getcmd();
  2602.     if (port->mode & gone) return;
  2603.     switch (*port->fld[0])
  2604.     {
  2605. #ifdef MCH_AMIGA
  2606.       case 'L' :
  2607.          if(port->mmhs->type == 'B') {
  2608.             life = atoi(port->fld[1]);
  2609.             if((life >= 0) && (life < 256))port->mmhs->lifetime = life;
  2610.          }
  2611.          /* This 'L' command confuses prthdr(). So unconfuse it */
  2612.          port->opt1 = ' ';
  2613.          break;
  2614. #endif
  2615.       case 'T' : pcall(port->mmhs->to, port->fld[1]); break;
  2616.       case 'F' : pcall(port->mmhs->from, port->fld[1]); break;
  2617.       case 'B' : edbbs(1); break;
  2618.       case 'I' : if (*port->fld[1])
  2619.        {
  2620.          remnl(port->line);
  2621.          strncpy(port->mmhs->title, port->line+2, mhtitl);
  2622.        }
  2623.        else *port->mmhs->title = '\0';
  2624.        break;
  2625.       case 'S' : switch(*port->fld[1])
  2626.        {
  2627.          case 'F' : port->mmhs->stat = m_fwd;   break;
  2628.          case 'H' : port->mmhs->stat = m_hold;  break;
  2629.          case 'N' : port->mmhs->stat = 0;       break;
  2630.          case 'O' : port->mmhs->stat = m_stale; break;
  2631.          case 'Y' : port->mmhs->stat = m_read;  break;
  2632.          case '$' : port->mmhs->stat setbit m_bull; break;
  2633.        }
  2634.        break;
  2635.       case 'Y' : if(*port->fld[1]) port->mmhs->type = *port->fld[1];
  2636.        else port->mmhs->type = ' '; break;
  2637.  
  2638.       case 'D' : if(*port->fld[1]) strncpy(port->mmhs->bid, port->fld[1], ln_bid);
  2639.        else fill(port->mmhs->bid, ' ', ln_bid);
  2640.        break;
  2641.     }
  2642.   }
  2643.   wt_mmhs();
  2644.   makehdr2();
  2645.   if (*port->mmhs->bid isnt ' ')
  2646.   {
  2647.     checkbid();
  2648.     if  (needbid)
  2649.     {
  2650. #ifdef MCH_AMIGA
  2651.       lock_bid();
  2652. #endif
  2653.       if ((out = fopen(bidfile,"a")) is NULL)
  2654.       {
  2655. #ifdef MCH_AMIGA
  2656.    unlock_bid();
  2657. #endif
  2658.    port->msg = mcant; return; 
  2659.       }
  2660.  
  2661.       a = port->cmd;
  2662.       b = port->mmhs->bid;
  2663.       unbl(a, b, ln_bid);      
  2664.  
  2665.       sprintf(port->line, "%4.4s%s\n", port->mmhs->date + 2, port->cmd);
  2666.       if (s_flag & s_dv) begin_lock();
  2667.       fputs(port->line, out);
  2668.       if (s_flag & s_dv) end_lock();
  2669.       fclose(out);
  2670. #ifdef MCH_AMIGA
  2671.    unlock_bid();
  2672. #endif
  2673.     }
  2674.   }
  2675. }
  2676.  
  2677. /*
  2678.  *  ET command, edit an NTS traffic message header.
  2679.  */
  2680.  
  2681. edtfc()
  2682. {
  2683.   register short ok;
  2684.  
  2685.   if (!findmsg(atoi(port->fld[1]))) { port->msg = mnmsg; return; }
  2686.   prthdr(true, true);
  2687.  
  2688.   ok = (port->mmhs->type is 'T');
  2689.   if (!ok) ok = ((port->mmhs->type is ' ') and matchn(port->mmhs->to, "NTS", 3));
  2690.   if (!ok) { port->msg = mm[12]; return; }
  2691.  
  2692.   prtx(mm[8]);
  2693.   getcmd();
  2694.   if (port->mode & gone) return;
  2695.   if (port->flds) pcall(port->mmhs->to, port->fld[0]);
  2696.  
  2697.   prtx(mm[9]);
  2698.   getcmd();
  2699.   if (port->mode & gone) return;
  2700.   edbbs(0);
  2701.  
  2702.   prtx(mm[10]);
  2703.   getcmd();
  2704.   if (port->mode & gone) return;
  2705.   if (port->flds)
  2706.   {
  2707.     remnl(port->line);
  2708.     strncpy(port->mmhs->title, port->line, mhtitl);
  2709.   }
  2710.   else if (*port->line is ' ') *port->mmhs->title = '\0';
  2711.  
  2712.   prtx(mm[11]);
  2713.   getcmd();
  2714.   if (port->mode & gone) return;
  2715.   if (port->flds) port->mmhs->type = *port->fld[0];
  2716.   else if (*port->line is ' ') port->mmhs->type = ' ';
  2717.  
  2718.   port->mmhs->stat = 0;
  2719.   prthdr(true, true);
  2720.   wt_mmhs();
  2721.   makehdr2();
  2722.   sprintf(port->line, "%u %-.6s %s",
  2723.     port->mmhs->number, port->mmhs->to, port->mmhs->title);
  2724.   log('M', 'E', port->opt2, port->line);
  2725. }
  2726.  
  2727. edbbs(f)
  2728. int f;
  2729. {
  2730.   fill(port->mmhs->call, '\0', 92);
  2731.   port->mmhs->ext = 0;
  2732.   fill(port->mmhs->bbs, ' ', ln_call);
  2733.   if(*port->fld[f])
  2734.   {
  2735.     pcall(port->mmhs->bbs, port->fld[f]);
  2736.     if (strchr(port->fld[f], '.') is NULL) dodis();
  2737.     else
  2738.     {
  2739.       port->mmhs->ext = 2;
  2740.       strncpy(port->mmhs->call[0], port->fld[f], ln_hier);
  2741.     }
  2742.     if (port->mmhs->ext is 0) chkhier();
  2743.   }
  2744. }
  2745.  
  2746. /*
  2747.  *  Check to see if bbs has match in STATES.MB file and add state code
  2748.  *  to hierarchical call.
  2749.  */
  2750.  
  2751. chkhier()
  2752. {
  2753.   FILE *hier;
  2754.   char hiercall[ln_call], bbs[ln_call+1], phier[ln_hier];
  2755.   char *p;
  2756. #ifdef MCH_AMIGA
  2757.    register char *q;
  2758. #endif
  2759.  
  2760.   if (*port->mmhs->bbs is ' ') return;
  2761.   if(( hier = fopen( stfile, "r")) is NULL) return;
  2762.   while( fgets( tmp->scr, linelen, hier) isnt NULL)
  2763.   {
  2764.     pcall(hiercall, tmp->scr);
  2765.     if( wcm(hiercall, port->mmhs->bbs))
  2766.     {
  2767. #ifndef MCH_AMIGA
  2768.       remnl(tmp->scr);
  2769. #endif
  2770.       p = strchr(tmp->scr, '.');
  2771.       unbl(bbs, port->mmhs->bbs, ln_call);
  2772.       unbl(phier, p, ln_hier);
  2773. #ifdef MCH_AMIGA
  2774. /* If the hierarchical portion has .USA or .CAN on the end then add .NA */
  2775.       for(q=phier;*q;q++);
  2776.       p = q;
  2777.       while((q > phier) && (*q != '.'))q--;
  2778.       if(matchn(".USA",q,4) || matchn(".CAN",q,4)) {
  2779.          strcpy(p,".NA");
  2780.       }
  2781. #endif
  2782.       port->mmhs->ext = 2;
  2783.       fill( port->mmhs->call[0], '\0', 92);
  2784.       sprintf( port->mmhs->call[0], "%s%s", bbs, phier);
  2785.       fclose(hier);
  2786.       return;
  2787.     }
  2788.    }
  2789.    fclose(hier);
  2790.    return;
  2791.  }
  2792.  
  2793. /*
  2794.  * Compress the bidfile by removing old bids 
  2795.  */
  2796.  
  2797. cprs_bid()
  2798. {
  2799.   FILE *bfl, *bbfl;
  2800.   int x, yy, zz;
  2801.   char biddate[7];
  2802.  
  2803.   unlink(bbidfile);
  2804.   rename(bidfile, bbidfile);
  2805.   unlink(bidfile);
  2806.  
  2807.   if ((bfl = fopen(bidfile, "a")) is NULL)
  2808.   {
  2809. #ifndef MCH_AMIGA
  2810.     printf("Error opening %s\n", bidfile);
  2811. #else
  2812.     sprintf(tmpstr,"Error opening %s\n", bidfile);
  2813.     ttputs(tmpstr);
  2814. #endif
  2815.     return;
  2816.   }
  2817.   if ((bbfl = fopen(bbidfile, "r")) is NULL)
  2818.   {
  2819.     nofile(bbidfile);
  2820.     return;
  2821.   }
  2822.  
  2823.   yy=0; zz=0;
  2824. #ifndef MCH_AMIGA
  2825.   printf("Compressing bid file.......\n");
  2826. #else
  2827. /* NOTE that this routine is called at the same time as a GM is done and
  2828.    there is already a lock on the whole system when this function executes
  2829.    so there's no need to lock the BID semaphore.
  2830. */
  2831.   ttputs("Compressing bid file.......\n");
  2832. #endif
  2833.   while (fgets(port->line, linelen, bbfl) isnt NULL)
  2834.   {
  2835.     fill (biddate, ' ', 6);
  2836.     strncpy (biddate + 2, port->line, 4);
  2837.     yy++;
  2838.     if ((x = ddiff(biddate, l_date, false)) < 0)
  2839.       x += 365;
  2840.     if (x < bidnum)
  2841.       {
  2842.    fputs (port->line, bfl);
  2843.    zz++;
  2844.       }
  2845.   }
  2846. #ifndef MCH_AMIGA
  2847.   printf("There were %d records, now %d remain\n",yy,zz);
  2848.   printf("Compression completed\n");
  2849. #else
  2850.   sprintf(tmpstr,"There were %d records, now %d remain\n",yy,zz);
  2851.   ttputs(tmpstr);
  2852.   ttputs("Compression completed\n");
  2853.    /* Get the BID semaphore and set the new length of file */
  2854. #endif
  2855.   
  2856.   fclose (bfl);
  2857.   fclose (bbfl);
  2858. }
  2859.  
  2860. #ifdef MCH_AMIGA
  2861. check_mail()
  2862. {
  2863.    extern long get_mail();
  2864.    lock_mail();
  2865.    if(mfhs->count != get_mail()) {
  2866.       close(mfl);
  2867.       mfl = open(mbfile, O_RDWR | O_BINARY);
  2868.       read_rec(mfl, 0, (char *)mfhs);
  2869.       titles();
  2870.    }
  2871. }
  2872. #endif
  2873.